Contents

Basics

Working With Databases

How to Use Windows ISQL

How to Use Server Manager

SQL Language Reference

Error Codes and Messages


Basics

About Help

What Is the Borland Local InterBase Server?

The Borland Local InterBase Server is a single-user Windows-based version of Borland's InterBase Workgroup Server, an SQL-compliant relational database management system (RDBMS). The Local InterBase Server includes Windows ISQL and the Server Manager, a Windows tool that can be used with Local InterBase Server or a remote InterBase server. Using the Local InterBase Server, you can access local databases through Windows ISQL or through an SQL application program.

The Local InterBase Server can be used in three ways:

As an intermediate step in upsizing, between the desktop and server, providing a local SQL engine for development of SQL-specific features.

As a local database engine for stand-alone desktop SQL applications.

As a local environment for developing a client/server application.

Other basic information you need:

Features

Limits

Conventions

File Specifications

Reserved Words

System Tables and Views

Database Objects and Concepts

Database Design

Working With Databases

Working With Transactions

Using the Example Database


About Help

The Local InterBase Server online Help provides experienced database designers with the necessary information to define an InterBase database using Windows ISQL and the Server Manager. If you have little or no experience creating relational databases using SQL, refer to the many available sources about SQL and relational database management systems.


Features

InterBase offers all the benefits of a fully relational DBMS. The following table lists some of the key InterBase features:

Feature	Description

SQL-92 entry-level conformance	ANSI standard SQL, available through an Interactive SQL tool and Borland desktop applications.
Simultaneous access to multiple databases	One application can access many databases at the same time.
Multi-generational architecture	Server maintains older versions of records (as needed) so that transactions can see a consistent view of data.
Query optimization	Server optimizes queries automatically, or user may manually specify query plan.
BLOB data type	Binary Large Objects can contain unformatted data such as graphics and text.
Declarative referential integrity	Automatic enforcement of cross-table relationships (between FOREIGN and PRIMARY KEYs.)
Stored procedures	Programmatic elements in the database for advanced queries and data manipulation actions.
Triggers	Self-contained program modules that are activated when data in a specific table is inserted, updated, or deleted.
Updatable views	Views can reflect data changes as they occur.
Outer joins	Relational construct between two tables that enables complex operations.
Explicit transaction management	Full control of transaction start, commit, and rollback, including named transactions.
Concurrent multiple application access to data	One application reading a table does not necessarily block others from it.
Automatic two-phase commit	Multi-database transactions check that changes to all databases happen before committing.
Multi-dimensional arrays	Column data types arranged in an indexed list of elements.
Server Manager	Windows tool for database backup, restoration, maintenance, and security.
Windows ISQL	Interactive data definition and query tool for Windows.


Limits

All limits are subject to the restrictions imposed by operating system and hardware considerations.

Object	Limit
Database size	10 GB or less.
Files per database	65,536 The metadata allows a SHORT number of files.
Databases open in one transaction	No architectural limit.
Tables per database	65,536 (Numbered using a SHORT).
Rows and columns per table	No Limit. Record can be 64K. Number of columns created depends on data types used.
Row size	64K
Indices per database	64K (Can be on a single table).
Indices per table	64K
Events per trigger	No limit.
Events per stored procedure	No limit.
Blob size	64K
Array size	64K
Tables joined	No limit.
Query nesting levels	No limit.
Columns per one composite index	16
Levels of nesting per stored procedure	100
Levels of nesting per trigger	1000
Stored procedure size	48K
Key in sort clause	64K
Trigger size	48K
Query control	(Local) single-user model.
Database Sweep	By default, every 20,000 transactions.


Conventions

Syntax Conventions

Database Object-naming Conventions

File-naming Conventions


Syntax Conventions

The following table describes the conventions used in syntax statements and sample code, and offers examples of their use:

Convention	Purpose	Example

UPPERCASE	Keywords that must be typed exactly as they appear when used.	SET TERM !!;
italic	Parameters that cannot be broken into smaller units. For example, a table name cannot be subdivided.	CREATE TABLE name (<col> [, <col> ...]);
<italic>	Parameters in angle brackets that can be broken into smaller syntactic units. For example, column definitions (<col>) can be subdivided into a name, data type and constraint definition.	CREATE TABLE name (<col> [, <col> ...]); <col> = name <datatype> [CONSTRAINT name <type>]
[ ]	Square brackets enclose optional syntax.	<col> [, <col> ...]
...	Closely spaced ellipses indicate that a clause within brackets can be repeated as many times as necessary.	(<col> [, <col> ...]);
|	The pipe symbol indicates that either of two syntax clauses that it separates may be used, but not both.  Inside curly braces, the pipe symbol separates multiple choices, one of which must be used.	SET TRANSACTION {SNAPSHOT [TABLE STABILITY] | READ COMMITTED};
{ }	Curly braces indicate that one of the enclosed options must be included in actual statement use.	SET TRANSACTION {SNAPSHOT [TABLE STABILITY] | READ COMMITTED};


Database Object-naming Conventions

InterBase database objects, such as tables, views, and column names, appear in text and code in uppercase in the InterBase documentation set because this is the way such information is stored in a database's system tables.

When an applications programmer or end user creates a database object or refers to it by name, case is unimportant. The following limitations on naming database objects must be observed:

Start each name with an alphabetic character (A-Z or a-z).

Restrict object names to 31 characters, including dollar signs ($), underscores (_), 0 to 9, A to Z, and a to z. Some objects, such as constraint names, are restricted to 27 bytes in length.

Keep object names unique. In all cases, objects of the same type, for example, tables and views, must be unique. In most cases, object names must also be unique within the database.


File-naming Conventions

InterBase is available on a wide variety of platforms. In most cases users in a heterogeneous networking environment can access their InterBase database files regardless of platform differences between client and server machines if they know the target platform's file naming conventions.

Because file-naming conventions differ widely from platform to platform, and because the core InterBase documentation set is the same for each of these platforms, all file names in text and in examples are restricted to a base name with a maximum of eight characters, with a maximum extension length of three characters. For example, the example database on all servers is referred to as employee.gdb.

Generally, InterBase fully supports each platform's file-naming conventions, including the use of node and path names. InterBase, however, recognizes two categories of file specification in commands and statements that accept more than one file name. The first file specification is called the primary file specification. Subsequent file specifications are called secondary file specifications. Some commands and statements place restrictions on using node names with secondary file specifications.

In syntax, file specification is denoted as follows:

"<filespec>"


File Specifications

Primary File Specifications

InterBase syntax always supports a full file specification, including optional node name and full path, for primary file specifications. For example, the syntax notation for CREATE DATABASE appears as follows:

CREATE {DATABASE | SCHEMA} "<filespec>"
[USER "username" [PASSWORD "password"]]
[PAGE_SIZE [=] int]
[LENGTH [=] int [PAGE[S]]]
[DEFAULT CHARACTER SET charset]
. . .

In this syntax, the <filespec> that follows CREATE DATABASE supports a node name and path specification, including a platform-specific drive or volume specification.

Secondary File Specifications

For InterBase syntax that supports multiple file specification, such as CREATE DATABASE, all file specifications after the first are secondary. Secondary file specifications generally cannot include a node name, but may specify a full path name. For example, the syntax notation for CREATE DATABASE appears as follows:

CREATE {DATABASE | SCHEMA} "<filespec>"
[USER "username" [PASSWORD "password"]]
[PAGE_SIZE [=] int]
[LENGTH [=] int [PAGE[S]]]
[DEFAULT CHARACTER SET charset]
[<secondary_file>]

<secondary_file> = FILE "<filespec>" [<fileinfo>] [<secondary_file>]

<fileinfo> = LENGTH [=] int [PAGE[S]] | STARTING [AT [PAGE]] int [<fileinfo>]

In the secondary file specification, <filespec> does not support specification of a node name.


InterBase Keywords
InterBase Reserved Words

The tables below list reserved words, words reserved from use in SQL programs and ISQL (Interactive SQL). The list includes SQL, DSQL, ISQL, and gpre reserved words.

Reserved words are defined for special purposes, and are sometimes called keywords. A keyword cannot occur in a user-declared identifier or as the name of a table, column, index, trigger, or constraint. Keywords are:

Part of statements

Used as statements

Names of standard data structures or data types

A

ACTIVE	AS

ADD	ASC

AFTER	ASCENDING

ALL	AT

ALTER	AUTO

AND	AUTODDL

ANY	AVG

B

BASED	BETWEEN

BASENAME	BLOB

BASE_NAME	BLOBEDIT

BEFORE	BUFFER

BEGIN	BY

C

CACHE 	COMPILETIME

CAST 	COMPUTED

CHAR 	CLOSE

CHARACTER 	CONDITIONAL

CHARACTER_LENGTH 	CONNECT

CHAR_LENGTH 	CONSTRAINT

CHECK 	CONTAINING

CHECK_POINT_LEN 	CONTINUE

CHECK_POINT_LENGTH 	COUNT

COLLATE 	CREATE

COLLATION 	CSTRING

COLUMN 	CURRENT

COMMIT 	CURSOR

COMMITTED

D

DATABASE 	DESCENDING

DATE 	DESCRIBE

DB_KEY 	DESCRIPTOR

DEBUG 	DISCONNECT

DEC 	DISPLAY

DECIMAL	DISTINCT

DECLARE	DO

DEFAULT 	DOMAIN

DELETE 	DOUBLE

DESC	DROP

E

ECHO	EXCEPTION

EDIT	EXECUTE

ELSE 	EXISTS

END 	EXIT

ENTRY_POINT 	EXTERN

ESCAPE 	EXTERNAL

EVENT 	EXTRACT

F

FETCH	FOREIGN

FILE 	FOUND

FILTER 	FROM

FLOAT 	FULL

FOR 	FUNCTION

G

GDSCODE	GRANT

GENERATOR	GROUP

GEN_ID	COMMIT_GROUP_WAIT

GLOBAL	GROUP_COMMIT_WAIT_TIME

GOTO

H

HAVING	HELP

I

IF 	INPUT_TYPE

IMMEDIATE 	INSERT

IN	INT

INACTIVE 	INTEGER

INDEX	INTO

INDICATOR 	IS

INIT 	ISOLATION

INNER	ISQL

INPUT

J

JOIN

K

KEY

L

LC_MESSAGES 	LIKE

LC_TYPE 	LOGFILE

LEFT 	LOG_BUFFER_SIZE

LENGTH 	LOG_BUF_SIZE

LEV 	LONG

LEVEL

M

MANUAL 	MERGE

MAX 	MESSAGE

MAXIMUM 	MIN

MAXIMUM_SEGMENT	MINIMUM

MAX_SEGMENT 	MODULE_NAME

N

NAMES 	NOT

NATIONAL 	NULL

NATURAL 	NUMERIC

NCHAR	NUM_LOG_BUFS

NO	NUM_LOG_BUFFERS

NOAUTO

O

OCTET_LENGTH	OR

OF 	ORDER

ON 	OUTER

ONLY	OUTPUT

OPEN	OUTPUT_TYPE

OPTION	OVERFLOW

P

PAGE	POST_EVENT

PAGELENGTH 	PRECISION

PAGES 	PREPARE

PAGE_SIZE	PROCEDURE

PARAMETER 	PROTECTED

PASSWORD 	PRIMARY

PLAN 	PRIVILEGES

POSITION 	PUBLIC

Q

QUIT

R

RAW_PARTITIONS 	RETAIN

RDB$DB_KEY 	RETURN

READ 	RETURNING_VALUES

REAL 	RETURNS

RECORD_VERSION	REVOKE

REFERENCES 	RIGHT

RELEASE 	ROLLBACK

RESERV	RUNTIME

RESERVING

S

SCHEMA 	SQL

SEGMENT 	SQLCODE

SELECT 	SQLERROR

SET 	SQLWARNING

SHADOW 	STABILITY

SHARED 	STARTING

SHELL 	STARTS

SHOW 	STATEMENT

SINGULAR 	STATIC

SIZE 	STATISTICS

SMALLINT 	SUB_TYPE

SNAPSHOT 	SUM

SOME	SUSPEND

SORT

T

TABLE 	TRANSLATE

TERMINATOR 	TRANSLATION

THEN 	TRIGGER

TO 	TRIM

TRANSACTION

U

UNCOMMITTED	UPPER

UNION 	USER

UNIQUE	USING

UPDATE

V

VALUE	VARYING

VALUES	VERSION

VARCHAR	VIEW

VARIABLE

W

WAIT	WHILE

WHEN	WITH

WHENEVER	WORK

WHERE	WRITE


System Tables and Views

The InterBase system tables contain and track metadata. InterBase automatically creates system tables when a database is created. Each time a user creates or modifies metadata through data definition, the SQL data definition utility automatically updates the system tables.

The SQL system views provide information about existing integrity constraints for a database. They are a subset of views defined in the SQL-92 standard. System views are created separately by running an ISQL script after database definition.

To see system tables, use this ISQL command:

SHOW SYSTEM TABLES;

The following ISQL command lists system views along with database views:

SHOW VIEWS;


System Tables

This table lists the InterBase system tables. The names of system tables and their columns start with RDB$.

RDB$CHARACTER_SETS	RDB$LOG_FILES

RDB$CHECK_CONSTRAINTS	RDB$PAGES

RDB$COLLATIONS	RDB$PROCEDURE_PARAMETERS

RDB$DATABASE	RDB$PROCEDURES

RDB$DEPENDENCIES	RDB$REF_CONSTRAINTS

RDB$EXCEPTIONS	RDB$RELATION_CONSTRAINTS

RDB$FIELD_DIMENSIONS	RDB$RELATION_FIELDS

RDB$FIELDS	RDB$RELATIONS

RDB$FILES	RDB$SECURITY_CLASSES

RDB$FILTERS	RDB$TRANSACTIONS

RDB$FORMATS	RDB$TRIGGER_MESSAGES

RDB$FUNCTION_ARGUMENTS	RDB$TRIGGERS

RDB$FUNCTIONS	RDB$TYPES

RDB$GENERATORS	RDB$USER_PRIVILEGES

RDB$INDEX_SEGMENTS	RDB$VIEW_RELATIONS

RDB$INDICES


System Views

The four views provide information about existing integrity constraints for a database. They must be created after a database is created. SQL system views are a subset of system views defined in the SQL-92 standard. Since they are not defined by InterBase, the names of the system views and their columns do not start with RDB$.

CHECK_CONSTRAINTS	REFERENTIAL_CONSTRAINTS

CONSTRAINTS_COLUMN_USAGE	TABLE_CONSTRAINTS


RDB$CHARACTER_SETS

RDB$CHARACTER_SETS describes the valid character sets available in InterBase.

Column Name	Type/length	Description

CHARACTER_SET_NAME	CHAR/31	Name of a character set that InterBase recognizes.

FORM_OF_USE	CHAR/31	Reserved for internal use. Subtype 2.

NUMBER_OF_CHARACTERS	INTEGER	Number of characters in a particular character set. For example, the set of Japanese characters.

DEFAULT_COLLATE_NAME	CHAR/31	Subtype 2. Default collation sequence for the character set.

CHARACTER_SET_ID	SMALLINT	A unique identification for the character set.

SYSTEM_FLAG	SMALLINT	Indicates whether the character set is User-defined (value of 0) or System-defined (value of 1).

DESCRIPTION	BLOB/80	Subtype text. Contains a user-written description of the character set.

FUNCTION_NAME	CHAR/31	Reserved for internal use. Subtype 2.

BYTES_PER_CHARACTER	SMALLINT	Size of character in bytes.


RDB$CHECK_CONSTRAINTS

RDB$CHECK_CONSTRAINTS stores database integrity constraint information for CHECK constraints. In addition, the table stores information for constraints implemented with NOT NULL.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Subtype 2. Name of a CHECK or NOT NULL constraint.

TRIGGER_NAME	CHAR/31	Subtype 2. Name of the trigger that enforces the CHECK constraint. For a NOT NULL constraint, name of the source column in RDB$RELATION_FIELDS.


RDB$COLLATIONS

RDB$COLLATIONS records the valid collating sequences available for use in InterBase.

Column Name	Type/length	Description

COLLATION_NAME	CHAR/31	Name of a valid collation sequence in InterBase.

COLLATION_ID	SMALLINT	Unique identifier for the collation sequence.

CHARACTER_SET_ID	SMALLINT	Identifier of the underlying character set of this collation sequence. Required before collation can proceed; determines which character set is in use. Corresponds to the RDB$CHARACTER_SET_ID column in the RDB$CHARACTER_SETS table.

COLLATION_ATTRIBUTES	SMALLINT	Reserved for internal use.

SYSTEM_FLAG	SMALLINT	Indicates whether the generator is User-defined (value of 0) or System-defined (value greater than 0).

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the collation sequence.

FUNCTION_NAME	CHAR/31	Reserved for internal use.


RDB$DATABASE

RDB$DATABASE defines a database.

Column Name	Type/length	Description

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the database. When a comment is included in a CREATE or ALTER SCHEMA | DATABASE statement, ISQL writes to this column.

RELATION_ID	SMALLINT	For internal use by InterBase.

SECURITY_CLASS	CHAR/31	Subtype 2. Security class defined in the RDB$SECURITY_CLASSES table. The access control limits described in the named security class apply to all database usage.

CHARACTER_SET_NAME	CHAR/31	Subtype 2. Name of character set.


RDB$DEPENDENCIES

RDB$DEPENDENCIES keeps track of the tables and columns upon which other system objects depend. These objects include views, triggers, and computed columns. InterBase uses this table to ensure that a column or table cannot be deleted if it is used by any other object.

Column Name	Type/length	Description

DEPENDENT_NAME	CHAR/31	Subtype 2. Names the object this table tracks: a view, trigger, or computed column.

DEPENDED_ON_NAME	CHAR/31	Subtype 2. Names the table referenced by the object named above.

FIELD_NAME	CHAR/31	Subtype 2. Names the column referenced by the object named above.

DEPENDENT_TYPE	SMALLINT	Describes the object type of the object referenced in the RDB$DEPENDENT_NAME column.

DEPENDED_ON_TYPE	SMALLINT	Describes the object type of the object referenced in the RDB$DEPENDED_ON_NAME column.


Type Codes

The following table lists the type codes for the DEPENDENT_TYPE and DEPENDED_ON_TYPE columns in the RDB$DEPENDENCIES system table:

Code	Description

0	table

1	view

2	trigger

3	computed_field

4	validation

5	procedure

6	expression_index

7	exception

8	user

9	field

10	index

All other values are reserved for future use.


RDB$EXCEPTIONS

RDB$EXCEPTIONS describes error conditions related to stored procedures, including user-defined exceptions.

Column Name	Type/length	Description

EXCEPTION_NAME	CHAR/31	Subtype 2. Exception name.

EXCEPTION_NUMBER	INTEGER	Number for the exception.

MESSAGE	VARCHAR/78	Text of exception message.

DESCRIPTION	BLOB/80	Subtype Text. Text description of the exception.

SYSTEM_FLAG	SMALLINT	Indicates whether the exception is User-defined (value of 0) or System-defined (value greater than 0).


RDB$FIELD_DIMENSIONS

DB$FIELD_DIMENSIONS describes each dimension of an array column.

Column Name	Type/length	Description

FIELD_NAME	CHAR/31	Subtype 2. Names the array column described by this table. The column name must exist in the RDB$FIELD_NAME column of RDB$FIELDS.

DIMENSION	SMALLINT	Identifies one dimension of the array column. The first dimension is identified by the integer 0.

LOWER_BOUND	INTEGER	Indicates the lower bound of the previously specified dimension.

UPPER_BOUND	INTEGER	Indicates the upper bound of the previously specified dimension.


RDB$FIELDS

RDB$FIELDS defines the characteristics of a column. Each domain or column has a corresponding row in RDB$FIELDS. Columns are added to tables by means of an entry in the RDB$RELATION_FIELDS table, which describes local characteristics.

For domains, RDB$FIELDS includes domain name, null status, and default values. SQL columns are defined in RDB$RELATION_FIELDS. For both domains and simple columns, RDB$RELATION_FIELDS may contain default and null status information.

Column Name	Type/length	Description

FIELD_NAME	CHAR/31	Unique name of a domain or system-assigned name for a column, starting with SQLnnn. The actual column names are stored in the RDB$FIELD_SOURCE column of RDB$RELATION_FIELDS.

QUERY_NAME	CHAR/31	Not used for SQL objects.

VALIDATION_BLR	BLOB/80	Not used for SQL objects.

VALIDATION_SOURCE	BLOB/80	Not used for SQL objects.

COMPUTED_BLR	BLOB/80	Subtype BLR. For computed columns, contains the BLR of the expression the database evaluates at the time of execution.

COMPUTED_SOURCE	BLOB/80	Subtype Text. For computed columns, contains the original CHAR source expression for the column.

DEFAULT_VALUE	BLOB/80	Stores default rule. Subtype BLR.

DEFAULT_SOURCE	BLOB/80	Subtype Text. SQL description of a default value.

FIELD_LENGTH	SMALLINT	Contains the length of the column defined in this row.

FIELD_SCALE	SMALLINT	Stores negative scale for numeric and decimal types.

FIELD_TYPE	SMALLINT	Specifies the data type of the column being defined. Changing the value of this column automatically changes the data type for all columns based on the column being defined.

FIELD_SUB_TYPE	SMALLINT	Used to distinguish types of BLOBs and CHAR columns.

MISSING_VALUE	BLOB/80	Not used for SQL objects.

MISSING_SOURCE	BLOB/80	Not used for SQL objects.

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the column being defined.

SYSTEM_FLAG	SMALLINT	For system tables.

QUERY_HEADER	BLOB/80	Not used for SQL objects.

SEGMENT_LENGTH	SMALLINT	Used for BLOB columns only; a non-binding suggestion for the length of BLOB buffers.

EDIT_STRING	VARCHAR/125	Not used for SQL objects.

EXTERNAL_LENGTH	SMALLINT	Length of the column as it exists in an external table. If the column is not in an external table, this value is 0.

EXTERNAL_SCALE	SMALLINT	Scale factor for an external column of an integer data type. The scale factor is the power of 10 by which the integer is multiplied.

EXTERNAL_TYPE	SMALLINT	Indicates the data type of the column as it exists in an external table.

DIMENSIONS	SMALLINT	For an array, specifies the number of dimensions in the array. For a non-array column, the value is 0.

NULL_FLAG	SMALLINT	Indicates whether a column can contain a NULL value. Values:
Empty: Can contain NULL values.
1: Cannot contain NULL values.

CHARACTER_LENGTH	SMALLINT	Length of character in bytes.

COLLATION_ID	SMALLINT	Unique identifier for the collation sequence.

CHARACTER_SET_ID	SMALLINT	ID indicating character set for the character or BLOB columns. Joins to the CHARACTER_SET_ID column of the RDB$CHARACTER_SETS system table.


Column Lengths

The following table lists column lengths for the FIELD_LENGTH column:

Type	Length

D_FLOAT	8

DOUBLE	8

DATE	8

BLOB	8

SMALLINT	2

INTEGER	4

QUAD	8

FLOAT	4


Field Type Values

The following table lists the valid values for the FIELD_TYPE column:

Type	Value

SMALLINT	7

INTEGER	8

QUAD	9

FLOAT	10

D_FLOAT	11

CHAR	14

DOUBLE	27

DATE	35

VARCHAR	37

BLOB	261

Restrictions:

The value of this column cannot be changed to or from BLOB.

Non-numeric data causes a conversion error in a column changed from CHAR to numeric.

Changing data from CHAR to numeric and back again adversely affects index performance. For best results, delete and recreate indexes when making this type of change.


Predefined Subtypes

The following tables list the predefined subtypes for BLOB and CHAR columns for the FIELD_SUB_TYPE column of the RBD$FIELDS system table:

BLOB Type	Description

0	unspecified

1	text

2	BLR (Binary Language Representation)

3	access control list

4	reserved for future use

5	encoded description of a table's current metadata

6	description of multi-database transaction that finished irregularly

CHAR Type	Description

0	unspecified

1	fixed BINARY data. Corresponds to the RDB$FIELD_SUB_TYPE column in the RDB$COLLATIONS table.


External Table Data Types

The following table lists the data types of columns as they exist in an external table:

Type	Value

SMALLINT	7

INTEGER	8

QUAD	9

FLOAT	10

D_FLOAT	11

CHAR	14

DOUBLE	27

DATE	35

VARCHAR	37

'C' string	40

BLOB	261

Note:	The "C" string is null terminated text.


RDB$FILES

RDB$FILES lists the secondary files and shadow files for a database.

Column Name	Type/length	Description

FILE_NAME	VARCHAR/253	Names either a secondary file or a shadow file for the database.

FILE_SEQUENCE	SMALLINT	Either the order that secondary files are to be used in the database or the order of files within a shadow set.

FILE_START	INTEGER	Specifies the starting page number for a secondary file or shadow file.

FILE_LENGTH	INTEGER	Specifies the file length in blocks.

FILE_FLAGS	SMALLINT	Reserved for system use.

SHADOW_NUMBER	SMALLINT	Set number of a shadow file. Set number indicates to which shadow set the file belongs. If the value of this column is 0 or missing, InterBase assumes the file being defined is a secondary file, not a shadow file.


RDB$FILTERS

RDB$FILTERS tracks information about a BLOB filter.

Column Name	Type/length	Description

FUNCTION_NAME	CHAR/31	Unique name for the filter defined by this row.

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the filter being defined.

MODULE_NAME	VARCHAR/253	Names the library where the filter executable is stored.

ENTRYPOINT	CHAR/31	The entry point within the filter library for the BLOB filter being defined.

INPUT_SUB_TYPE	SMALLINT	The BLOB subtype of the input data.

OUTPUT_SUB_TYPE	SMALLINT	The BLOB subtype of the output data.

SYSTEM_FLAG	SMALLINT	Indicates whether the filter is User-defined (value of 0) or System-defined (value greater than 0).


RDB$FORMATS

RDB$FORMATS keeps track of the formats of the columns in a table. InterBase assigns the table a new format number at each change to a column definition. This table allows existing application programs to access a changed table, without needing to be recompiled.

Column Name	Type/length	Description

RELATION_ID	SMALLINT	Names a table that exists in RDB$RELATIONS.

FORMAT	SMALLINT	Specifies the format number of the table. A table can have any number of different formats, depending on the number of updates to the table.

DESCRIPTOR	BLOB/80	Subtype Format. Lists each column in the table, along with its data type, length, and scale (if applicable).


RDB$FUNCTION_ARGUMENTS

RDB$FUNCTION_ARGUMENTS defines the attributes of a function argument.

Column Name	Type/length	Description

FUNCTION_NAME	CHAR/31	Unique name of the function with which the argument is associated. Must correspond to a function name in RDB$FUNCTIONS.

ARGUMENT_POSITION	SMALLINT	Position of the argument described in the RDB$FUNCTION_NAME column in relation to the other arguments.

MECHANISM	SMALLINT	Specifies whether the argument is passed by value (value of 0) or by reference (value of 1).

FIELD_TYPE	SMALLINT	Data type of the argument being defined.

FIELD_SCALE	SMALLINT	Scale factor for an argument that has an integer data type. The scale factor is the power of 10 by which the integer is multiplied.

FIELD_LENGTH	SMALLINT	Contains the length of the argument defined in this row.

FIELD_SUBTYPE	SMALLINT	Reserved for future use.

CHARACTER_SET_ID	SMALLINT	Unique numeric identifier for a character set.


RDB$FUNCTIONS

RDB$FUNCTIONS defines a user-defined function.

Column Name	Type/length	Description

FUNCTION_NAME	CHAR/31	Unique name for a function.

FUNCTION_TYPE	SMALLINT	Reserved for future use.

QUERY_NAME	CHAR/31	Alternate name for the function that can be used in ISQL.

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the function being defined.

MODULE_NAME 	VARCHAR/253	Names the function library where the executable function is stored.

ENTRYPOINT	CHAR/31	Entry point within the function library for the function being defined.

RETURN_ARGUMENT	SMALLINT	Position of the argument returned to the calling program. This position is specified in relation to other arguments.

SYSTEM_FLAG	SMALLINT	Indicates whether the function is User-defined (value of 0) or System-defined (value of 1).


RDB$GENERATORS

RDB$GENERATORS stores information about generators, which provide the ability to generate a unique identifier for a table.

Column Name	Type/length	Description

GENERATOR_NAME	CHAR/31	Name of the table to contain the unique identifier produced by the number generator.

GENERATOR_ID	SMALLINT	Unique system-assigned ID number for the generator.

SYSTEM_FLAG	SMALLINT	Indicates whether the generator is User-defined (value of 0) or System-defined (value greater than 0).


RDB$INDEX_SEGMENTS

RDB$INDEX_SEGMENTS specifies the columns that comprise an index for a table. Modifying these rows corrupts rather than changes an index unless the RDB$INDICES row is deleted and recreated in the same transaction.

Column Name	Type/length	Description

INDEX_NAME	CHAR/31	The index associated with this index segment. If the value of this column changes, the RDB$INDEX_NAME column in RDB$INDICES must also be changed.

FIELD_NAME	CHAR/31	The index segment being defined. The value of this column must match the value of the RDB$FIELD_NAME column in RDB$RELATION_FIELDS.

FIELD_POSITION	SMALLINT	Position of the index segment being defined. Corresponds to the sort order of the index.


RDB$INDICES

RDB$INDICES defines the index structures that allow InterBase to locate rows in the database more quickly. Because InterBase provides both simple indexes (a single-key column) and multi-segment indexes (multiple-key columns), each index defined in this table must have corresponding occurrences in the RDB$INDEX_SEGMENTS table.

Column Name	Type/length	Description

INDEX_NAME	CHAR/31	Names the index being defined. If the value of this column changes, change its value in the RDB$INDEX_SEGMENTS table.

RELATION_NAME	CHAR/31	Names the table associated with this index. The table must be defined in the RDB$RELATIONS table.

INDEX_ID	SMALLINT	Contains an internal identifier for the index being defined. Do not write to this column.

UNIQUE_FLAG	SMALLINT	Specifies whether the index allows duplicate values. Values:
0 - allows duplicate values
1 - does not allow duplicate values
Eliminate duplicates before creating a unique index.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the index. When including a comment in a CREATE INDEX or ALTER INDEX statement, ISQL writes to this column.

SEGMENT_COUNT	SMALLINT	Number of segments in the index. A value of 1 indicates a simple index.

INDEX_INACTIVE	SMALLINT	Indicates whether the index is Active (value of 0) or Inactive (value of 2).

INDEX_TYPE	SMALLINT	Reserved for future use.

FOREIGN_KEY	CHAR/31	Name of FOREIGN KEY constraint for which the index is implemented.

SYSTEM_FLAG	SMALLINT	Indicates whether the index is User-defined (value of 0) or System-defined (value greater than 0).

EXPRESSION_BLR	BLOB/80	Subtype BLR. Contains the BLR for the expression, evaluated by the database at execution time. Used for PC semantics.

EXPRESSION_SOURCE	BLOB/80	Subtype Text. Contains original text source for the column. Used for PC semantics.

STATISTICS	DOUBLE PRECISION	Selectivity factor for the index. Index selectivity, a measure of uniqueness for indexed columns, is used by the optimizer to choose an access strategy for a query.


RDB$LOG_FILES

RDB$LOG_FILES stores WAL protocol file information for a database.

Column Name	Type/length	Description

FILE_NAME	VARCHAR/253	Name of the current log file.

FILE_SEQUENCE	SMALLINT	Log file sequence file number.

FILE_LENGTH	INTEGER	Log file size in kilobytes.

FILE_PARTITIONS	SMALLINT	Number of log file partitions.

FILE_P_OFFSET	INTEGER

FILE_FLAGS	SMALLINT	Flags for RBD$LOG_FILES.


RDB$LOG_FILES Flags

The following table lists the flags for the FILE_FLAGS column:

Flag	Description

1	LOG_serial. Any serial log file, including default log configuration and overflow files.

2	LOG_default. If log file name is not specified, the default is database-name.log.n.

4	LOG_raw. On raw device.

8	LOG_overflow. Overflow files.


RDB$PAGES

RDB$PAGES keeps track of each page allocated to the database. Modifying this table in any way corrupts a database.

Column Name	Type/length	Description

PAGE_NUMBER	INTEGER	The physically allocated page number.

RELATION_ID	SMALLINT	Identifier number of the table for which this page is allocated.

PAGE_SEQUENCE	INTEGER	The sequence number of this page in the table to other pages allocated for the previously identified table.

PAGE_TYPE	SMALLINT	Describes the type of page. This information is for system use only.


RDB$PROCEDURE_PARAMETERS

RDB$PROCEDURE_PARAMETERS stores information about each parameter for each of a database's procedures.

Column Name	Type/length	Description

PARAMETER_NAME	CHAR/31	Parameter name.

PROCEDURE_NAME	CHAR/31	Name of the procedure in which the parameter is used.

PARAMETER_NUMBER	SMALLINT	Parameter sequence number.

PARAMETER_TYPE	SMALLINT	Parameter data type. Values are 0 = input or 1 = output.

FIELD_SOURCE	CHAR/31	Global column name.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the parameter.

SYSTEM_FLAG	SMALLINT	Indicates whether the parameter is User-defined (value of 0) or System-defined (value greater than 0).


RDB$PROCEDURES

RDB$PROCEDURES stores information about a database's stored procedures.

Column Name	Type/length	Description

PROCEDURE_NAME	CHAR/31	Procedure name.

PROCEDURE_ID	SMALLINT	Procedure number.

PROCEDURE_INPUTS	SMALLINT	Number of input parameters.

PROCEDURE_OUTPUTS	SMALLINT	Number of output parameters.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the procedure.

PROCEDURE_SOURCE	BLOB/80	Subtype Text. Source code for the procedure.

PROCEDURE_BLR	BLOB/80	Subtype BLR. BLR of the procedure source.

SECURITY_CLASS	CHAR/31	Security class of the procedure.

OWNER_NAME	CHAR/31	User who created the procedure. (Owner for SQL security purposes.)

RUNTIME	BLOB/80	Subtype Summary. Describes procedure metadata. Used for performance enhancement.

SYSTEM_FLAG	SMALLINT	Indicates whether the procedure is User-defined (value of 0) or System-defined (value greater than 0).


RDB$REF_CONSTRAINTS

RDB$REF_CONSTRAINTS stores referential integrity constraint information.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Name of a referential constraint.

CONST_NAME_UQ	CHAR/31	Name of a referenced PRIMARY KEY or UNIQUE constraint.

MATCH_OPTION	CHAR/7	Reserved for later use. Currently defaults to FULL.

UPDATE_RULE	CHAR/11	Reserved for later use. Currently defaults to RESTRICT.

DELETE_RULE	CHAR/11	Reserved for later use. Currently defaults to RESTRICT.


RDB$RELATION_CONSTRAINTS

RDB$RELATION_CONSTRAINTS stores information about integrity constraints for tables.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Name of a table constraint.

CONSTRAINT_TYPE	CHAR/11	Type of table constraint. Types are: PRIMARY KEY, UNIQUE, FOREIGN KEY, CHECK, and NOT NULL.

RELATION_NAME	CHAR/31	Name of the table for which the constraint is defined.

DEFERRABLE	CHAR/3	Reserved for later use. Currently defaults to No.

INITIALLY_DEFERRED	CHAR/3	Reserved for later use. Currently defaults to No.

INDEX_NAME	CHAR/31	Name of the index used by UNIQUE, PRIMARY KEY, or FOREIGN KEY constraints.


RDB$RELATION_FIELDS

For database tables, RDB$RELATION_FIELDS lists columns and describes column characteristics for domains.

SQL columns are defined in RDB$RELATION_FIELDS. The column name is correlated in the RDB$FIELD_SOURCE column to an underlying entry in RDB$FIELDS that contains a system name ("SQL$<n>"). This entry includes information about column type, length, etc. For both domains and simple columns, this table may contain default and nullability information.

Column Name	Type/length	Description

FIELD_NAME	CHAR/31	Name of the column whose characteristics being defined. The combination of the values in this column and in the RDB$RELATION_NAME column in this table must be unique.

RELATION_NAME	CHAR /31	Table to which a particular column belongs. A table with this name must appear in RDB$RELATIONS. The combination of the values in this column and in the RDB$FIELD column in this table must be unique.

FIELD_SOURCE	CHAR /31	The name for this column in the RDB$FIELDS table. If the column is based on a domain, contains the domain name.

QUERY_NAME	CHAR /31	Alternate column name for use in ISQL; supersedes the value in RDB$FIELDS.

BASE_FIELD	CHAR /31	Views only: The name of the column from RDB$FIELDS in a table or view that is the base for a view column being defined. For the base column: RDB$BASE_FIELD provides the column name. RDB$VIEW_CONTEXT, a column in this table, provides the source table name.

EDIT_STRING	VARCHAR /125	Not used in SQL.

FIELD_POSITION	SMALLINT	The position of the column in relation to other columns: ISQL obtains the ordinal position for displaying column values when printing rows from this column. gpre uses the column order for SELECT and INSERT statements. If two or more columns in the same table have the same value for this column, those columns appear in random order.

QUERY_HEADER	BLOB/80	Not used in SQL.

UPDATE_FLAG	SMALLINT	Not used by InterBase. Included for compatibility with other DSRI-based systems.

FIELD_ID	SMALLINT	Identifier for use in BLR to name the column. Because this identifier changes during backup and restoration of the database, try to use it in transient requests only. Do not modify this column.

VIEW_CONTEXT	SMALLINT	Alias used to qualify view columns by specifying the table location of the base column. It must have the same value as the alias used in the view BLR for this context stream.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the column being defined.

DEFAULT_VALUE	BLOB/80	Subtype BLR. BLR for default clause.

SYSTEM_FLAG	SMALLINT	Indicates whether the column is User-defined (value of 0) or System-defined (value greater than 0).

SECURITY_CLASS	CHAR/31	Names a security class defined in the RDB$SECURITY_CLASSES table. The access restrictions defined by this security class apply to all users of this column.

COMPLEX_NAME	CHAR/31	Reserved for future use.

NULL_FLAG	SMALLINT	Indicates whether the column may contain NULLs.

DEFAULT_SOURCE	BLOB/80	Subtype Text. SQL source to define defaults.

COLLATION_ID	SMALLINT	Unique identifier for the collation sequence.


RDB$RELATIONS

RDB$RELATIONS defines some of the characteristics of tables and views. Other characteristics, such as the columns included in the table and a description of each column, are stored in the RDB$RELATION_FIELDS table.

Column Name	Type/length	Description

VIEW_BLR	BLOB/80	Subtype BLR. For a view, contains the BLR of the query InterBase evaluates at the time of execution.

VIEW_SOURCE	BLOB/80	Subtype Text. For a view, contains the original source query for the view definition.

_DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the table being defined.

RELATION_ID	SMALLINT	Contains the internal identification number used in BLR requests. Do not modify this column.

SYSTEM_FLAG	SMALLINT	Indicates the contents of a table, either User-data (value of 0) or System information (value greater than 0). Do not set this column to 1 when creating tables.

DBKEY_LENGTH	SMALLINT	Length of the database key. Values: Tables = 8 and Views = 8 times the number of tables referenced in the view definition. Do not modify the value of this column.

FORMAT 	SMALLINT	For InterBase internal use only. Do not modify.

FIELD_ID 	SMALLINT	The number of columns in the table. This column is maintained by InterBase. Do not modify the value of this column.

RELATION_NAME	CHAR/31	The unique name of the table defined by this row.

SECURITY_CLASS	CHAR/31	Security class defined in the RDB$SECURITY_CLASSES table. Access controls defined in the security class apply to all uses of this table.

EXTERNAL_FILE	VARCHAR/253	The file in which the external table is stored. An external file can be either an Apollo AEGIS stream file or a VAX RMS file. If blank, the table does not correspond to an external file.

RUNTIME 	BLOB/80	Subtype Summary. Describes table metadata. Used for performance enhancement.

EXTERNAL_DESCRIPTION	BLOB/80	Subtype EXTERNAL_FILE_DESCRIPTION. User-written description of the external file.

OWNER_NAME	CHAR/31	Identifies the creator of the table or view. The creator is considered the owner for SQL security (GRANT/REVOKE) purposes.

DEFAULT_CLASS	CHAR/31	Default security class that InterBase applies to columns newly added to a table using the SQL security system.

FLAGS	SMALLINT


RDB$SECURITY_CLASSES

RDB$SECURITY_CLASSES defines access control lists and associates them with databases, tables, views, and columns in tables and views. For all SQL objects, the information in this table is duplicated in the RDB$USER_PRIVILEGES system table.

Column Name	Type/length	Description

SECURITY_CLASS	CHAR/31	Security class being defined. If the value of this column changes, change its name in the RDB$SECURITY_CLASS column in RDB$DATABASE, RDB$RELATIONS, and RDB$RELATION_FIELDS.

ACL	BLOB/80	Subtype ACL. Access control list that specifies users and the privileges granted to those users.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the security class being defined.


RDB$TRANSACTIONS

RDB$TRANSACTIONS keeps track of all multi-database transactions.

Column Name	Type/length	Description

TRANSACTION_ID	INTEGER	Identifies the multi-database transaction being described.

TRANSACTION_STATE	SMALLINT	Indicates the state of the transaction. Valid values are:
0 - limbo
1 - committed
2 - rolled back

TIMESTAMP	DATE	Reserved for future use.

TRANSACTION_DESCRIPTION	BLOB/80	Subtype TRANSACTION_DESCRIPTION. Describes a prepared multi-database transaction. This description is available if the reconnect fails.


RDB$TRIGGER_MESSAGES

RDB$TRIGGER_MESSAGES defines a trigger message and associates the message with a particular trigger.

Column Name	Type/length	Description

TRIGGER_NAME	CHAR/31	Names the trigger associated with this trigger message. The trigger name must exist in RDB$TRIGGERS.

MESSAGE_NUMBER	SMALLINT	The message number of the trigger message being defined. The maximum number of messages is 32,767.

MESSAGE	VARCHAR/78	The source for the trigger message.


RDB$TRIGGERS

RDB$TRIGGERS defines triggers.

Column Name	Type/length	Description

TRIGGER_NAME	CHAR/31	Names the trigger being defined.

RELATION_NAME	CHAR/31	Name of the table associated with the trigger being defined. This name must exist in RDB$RELATIONS.

TRIGGER_SEQUENCE	SMALLINT	Sequence number for the trigger being defined. Determines when a trigger is executed in relation to others of the same type. Triggers with the same sequence number execute in random order. If this number is not assigned by the user, InterBase assigns a value of 0.

TRIGGER_TYPE	SMALLINT	The type of trigger being defined.

TRIGGER_SOURCE	BLOB/80	Subtype Text. Original source of the trigger definition. The ISQL SHOW TRIGGERS statement displays information from this column.

TRIGGER_BLR	BLOB/80	Subtype BLR. BLR of the trigger source.

DESCRIPTION	BLOB/80	Subtype Text. User-written description of the trigger being defined. When including a comment in a CREATE TRIGGER or ALTER TRIGGER statement, ISQL writes to this column.

TRIGGER_INACTIVE	SMALLINT	Indicates whether the trigger being defined is Active (value of 0) or Inactive (value of 1).

SYSTEM_FLAG	SMALLINT	Indicates whether the trigger is User-defined (value of 0) or System-defined (value greater than 0).

FLAGS	SMALLINT


Trigger Types

The following table lists the types of triggers for the TRIGGER_TYPE column:

Value	Type

1	BEFORE INSERT

2	AFTER INSERT

3	BEFORE UPDATE

4	AFTER UPDATE

5	BEFORE DELETE

6	AFTER DELETE


RDB$TYPES

RDB$TYPES records enumerated data types and alias names for InterBase character sets and collation orders. This capability is not available in the current release.

Column Name	Type/length	Description

FIELD_NAME	CHAR/31	Column for which the enumerated data type is being defined.

TYPE	SMALLINT	Identifies the internal number that represents the column specified above.

TYPE_NAME	CHAR/31	Text that corresponds to the internal number.

DESCRIPTION	BLOB/80	Subtype Text. Contains a user-written description of the enumerated data type being defined.

SYSTEM_FLAG	SMALLINT	Indicates whether the data type is User-defined (value of 0) or System-defined (value greater than 0).


Type Codes

The following table lists the type codes (same as RDB$DEPENDENT_TYPES) for the TYPE column in the RDB$TYPES system table:

Code	Description

0	table

1	view

2	trigger

3	computed_field

4	validation

5	procedure

All other values are reserved for future use.


RDB$USER_PRIVILEGES

RDB$USER_PRIVILEGES keeps track of the privileges assigned to a user through an SQL GRANT statement. There is one occurrence of this table for each user/privilege intersection.

Column Name	Type/length	Description

USER	CHAR/31	Names the user who was granted the privilege listed in the following column, RDB$PRIVILEGE.

GRANTOR	CHAR/31	Names the user who granted the privilege.

PRIVILEGE	CHAR/6	Identifies the privilege granted to the user listed in the RDB$USER column, above. Valid values are: ALL, SELECT, DELETE, INSERT, or UPDATE.

GRANT_OPTION	SMALLINT	Indicates whether the privilege was granted with the WITH GRANT OPTION (value of 1) or not (value of 0). This option enables a user to grant the same authority to other users.

RELATION_NAME	CHAR/31	Identifies the table to which the privilege applies.

FIELD_NAME	CHAR/31	For update privileges, identifies the column to which the privilege applies.

USER_TYPE	SMALLINT

OBJECT_TYPE	SMALLINT


RDB$VIEW_RELATIONS

RDB$VIEW_RELATIONS is not used by SQL objects.

Column Name	Type/length	Description

VIEW_NAME	CHAR/31	Name of a view. The combination of RDB$VIEW_NAME and RDB$VIEW_CONTEXT must be unique.

RELATION_NAME	CHAR/31	Name of a table referenced in the view definition.

VIEW_CONTEXT	SMALLINT	Alias used to qualify view columns. Must have the same value as the alias used in the view BLR for this query.

CONTEXT_NAME	CHAR/31	Textual version of the alias identified in RDB$VIEW_CONTEXT. This variable must match the value of the RDB$VIEW_SOURCE column for the corresponding table in RDB$RELATIONS and be unique in the view.


CHECK_CONSTRAINTS

CHECK_CONSTRAINTS identifies all CHECK constraints defined in the database.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Unique name for the CHECK constraint. Nullable.

CHECK_CLAUSE	BLOB/80	Subtype Text. Nullable. Original source of the trigger definition, stored in the RDB$TRIGGER_SOURCE column in RDB$TRIGGERS.


CONSTRAINTS_COLUMN_USAGE

CONSTRAINTS_COLUMN_USAGE identifies columns used by PRIMARY KEY and UNIQUE constraints. For FOREIGN KEY constraints, this view identifies the columns defining the constraint.

Column Name	Type/length	Description

TABLE_NAME	CHAR/31	Table for which the constraint is defined. Nullable.

COLUMN_NAME	CHAR/31	Column used in the constraint definition. Nullable.

CONSTRAINT_NAME	CHAR/31	Unique name for the constraint. Nullable.


REFERENTIAL_CONSTRAINTS

REFERENTIAL_CONSTRAINTS identifies all referential constraints defined in a database.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Unique name for the constraint. Nullable.

UNIQUE_CONSTRAINT_NAME	CHAR/31	Name of the UNIQUE or PRIMARY KEY constraint corresponding to the specified referenced column list. Nullable.

MATCH_OPTION	CHAR/7	Reserved for future use. Always set to FULL. Nullable.

UPDATE_RULE	CHAR/11	Reserved for future use. Always set to RESTRICT. Nullable.

DELETE_RULE	CHAR/11	Reserved for future use. Always set to RESTRICT. Nullable.


TABLE_CONSTRAINTS

TABLE_CONSTRAINTS identifies all constraints defined in a database.

Column Name	Type/length	Description

CONSTRAINT_NAME	CHAR/31	Unique name for the constraint. Nullable.

TABLE_NAME	CHAR/31	Table for which the constraint is defined. Nullable.

CONSTRAINT_TYPE	CHAR/11	Possible values are UNIQUE, PRIMARY KEY, FOREIGN KEY, and CHECK. Nullable.

IS_DEFERRABLE	CHAR/3	Reserved for future use. Always set to No. Nullable.

INITIALLY_DEFERRED	CHAR/3	Reserved for future use. Always set to No. Nullable.


BLR

Binary Language Representation


The Example Database

The database, source code, and executables for these examples are contained in the EXAMPLES subdirectory of the InterBase directory (INTERBAS, by default).

The database (EMPLOYEE.GDB) is a personnel management and sales database for a fictional company corresponding to the database that is built in the tutorial. It is designed to include such InterBase features as FOREIGN KEY and CHECK constraints. Domains, triggers, and stored procedures are also defined for some of the tables.

The example database is made up of ten tables. Those tables are:

EMPLOYEE	DEPARTMENT

JOB	SALES

PROJECT	CUSTOMER

EMPLOYEE_PROJECT	PROJ_DEPT_BUDGET

COUNTRY	SALARY_HISTORY


Domains

Fifteen domains are defined for EMPLOYEE.GDB. Domains make table definition easier, because they predefine data types, CHECK constraints, and defaults.

Six domains are defined as simple data types without CHECK constraints or DEFAULT values.

Domain Name	Data Type

FIRSTNAME	(VARCHAR)

LASTNAME	(VARCHAR)

PHONENUMBER	(VARCHAR)

COUNTRYNAME	(VARCHAR)

ADDRESSLINE	(VARCHAR)

EMPNO	(SMALLINT)

Nine domains are defined with CHECK constraints and/or default values.

Name	Data Type	CHECK Constraint/Default

DEPTNO	CHAR(3)	CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)/None

PROJNO	CHAR(5)	CHECK (VALUE = UPPER (VALUE))/None

CUSTNO	INTEGER	CHECK (VALUE > 1000)/None

JOBCODE	VARCHAR(5)	CHECK (VALUE > '99999')/None

JOBGRADE	SMALLINT	CHECK (VALUE BETWEEN 0 AND 6)/None

SALARY	NUMERIC(10,2)	CHECK (VALUE > 0)/0

BUDGET	DECIMAL(12,2)	CHECK (VALUE > 10000 AND VALUE <= 2000000)/50000

PRODTYPE	VARCHAR(12)	CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))/'software'

PONUMBER	CHAR(8)	CHECK (VALUE STARTING WITH 'V')/None


Triggers

The example database contains the following triggers:

Name	Description

SET_EMP_NO	Creates a unique employee number when a new employee record is inserted.

SAVE_SALARY_CHANGE	Inserts a new record in the SALARY_HISTORY table when an employee's salary changes.

SET_CUST_NO	Creates a unique customer number when a new customer record is inserted.

POST_NEW_ORDER	Posts an event named "new_order" when a new record is inserted in the SALES table.


Stored Procedures

The example database contains the following stored procedures:

Name	Description

ADD_EMP_PROJ	Adds an employee to a project, returning an error message if the employee is not in the EMPLOYEE table.

DELETE_EMPLOYEE	Removes an employee's records in the EMPLOYEE, DEPARTMENT, and EMPLOYEE_PROJECT tables, unless the employee has any sales records in the SALES table.

GET_EMP_PROJ	Is a select procedure that returns all the projects to which an employee is assigned.

MAIL_LABEL	Creates a six-line customer mailing label, when given the customer number as input.

ORG_CHART	Returns an organization chart, showing department names and numbers, manager name and title, and number of employees in each department.

SHIP_ORDER	Takes a purchase order number (PO_NUMBER) as input, and updates the SALES table to indicate that an order has been shipped, unless it has already been shipped, the customer is on hold, or the customer has on overdue balance.

SUB_TOT_BUDGET	Returns the average, smallest, and largest department budgets for all departments in the department given as the input parameter.

DEPT_BUDGET	Takes a department number as input and returns the total budget of all departments under that department, inclusive.

SHOW_LANGS	Returns the language requirements for a job (stored in an array in the JOB table), when given the job code, grade, and country. This procedure illustrates how to display the contents of an array for a specific row and column.

ALL_LANGS	Uses SHOW_LANGS to return the language requirements for all jobs in the JOB table. This procedure illustrates how to display the contents of an array using a stored procedure for all rows in a table.


EMPLOYEE Table

Conceptually, the EMPLOYEE table is the central table in the database. There is one record in this table for each employee, with the employee number (EMP_NO column) as the primary key, because each employee is uniquely identified by an employee number. The DEPT_NO column is a foreign key that references the DEPARTMENT table. The columns JOB_CODE, JOB_GRADE, and JOB_COUNTRY reference the JOB table. The table also contains other information on each employee, such as salary and hire date. The salary is given in the currency in which the employee works.

The following table shows the contents of the EMPLOYEE table, the definition of each column in the table, and any relations to other tables (such as foreign keys).

Column Name	Data Type, Default Value, and CHECK Constraints
EMP_NO (EMPNO) PRIMARY KEY	SMALLINT NOT NULL
FIRST_NAME (FIRSTNAME)	VARCHAR(15) NOT NULL
LAST_NAME (LASTNAME)	VARCHAR(20) NOT NULL
PHONE_EXT	VARCHAR(4) Nullable
HIRE_DATE DATE	NOT NULL DEFAULT 'NOW'
DEPT_NO (DEPTNO) FOREIGN KEY - references DEPARTMENT (DEPT_NO)	CHAR(3) NOT NULL CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)
JOB_CODE (JOBCODE) FOREIGN KEY - references JOB	VARCHAR(5) NOT NULL CHECK (VALUE > '99999')
JOB_GRADE (JOBGRADE) FOREIGN KEY - references JOB	SMALLINT NOT NULL CHECK (VALUE BETWEEN 0 AND 6)
JOB_COUNTRY (COUNTRYNAME) FOREIGN KEY - references JOB	VARCHAR(15) NOT NULL
SALARY (SALARY)	DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (VALUE > 0)
FULL_NAME	Computed by: (last_name || ', ' || first_name)
There is also a complex CHECK constraint on SALARY:

CHECK (SALARY >= (SELECT MIN_SALARY FROM JOB WHERE
JOB.JOB_CODE = EMPLOYEE.JOB_CODE AND
JOB.JOB_GRADE = EMPLOYEE.JOB_GRADE AND
JOB.JOB_COUNTRY = EMPLOYEE.JOB_COUNTRY)
AND
SALARY <= (SELECT MAX_SALARY FROM JOB WHERE
JOB.JOB_CODE = EMPLOYEE.JOB_CODE AND
JOB.JOB_GRADE = EMPLOYEE.JOB_GRADE AND
JOB.JOB_COUNTRY = EMPLOYEE.JOB_COUNTRY))


DEPARTMENT Table

The DEPARTMENT table contains a record for each department in the company, with the DEPT_NO as the primary key. DEPARTMENT, the department name, is also a unique (or alternate) key. The HEAD_DEPT column is a foreign key referencing the parent department. So, in effect, the table defines a tree, in which each department can contain other departments. The "root" of the tree is the Corporate Headquarters department, for which HEAD_DEPT is NULL. The table also contains columns for each department's location, budget, and other information.

The following table shows the contents of the DEPARTMENT table.

Column Name	Data Type, Default Value, and CHECK Constraints
DEPT_NO (DEPTNO) PRIMARY KEY	CHAR(3) NOT NULL CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)
DEPARTMENT UNIQUE key	VARCHAR(25) NOT NULL
HEAD_DEPT (DEPTNO) FOREIGN KEY - references DEPARTMENT (DEPT_NO)	CHAR(3) NOT NULL CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)
MNGR_NO (EMPNO) FOREIGN KEY - references EMPLOYEE (EMP_NO)	SMALLINT Nullable
BUDGET (BUDGET)	DOUBLE PRECISION Nullable DEFAULT 50000 CHECK (VALUE > 10000 AND VALUE <= 2000000)
LOCATION	VARCHAR(15) Nullable
PHONE_NO (PHONENUMBER)	VARCHAR(20) Nullable DEFAULT '555-1234'


JOB Table

The JOB table contains a record for each job in the company. The three columns JOB_CODE, JOB_GRADE, and JOB_COUNTRY are the primary key that uniquely identifies a job. JOB_COUNTRY references the COUNTRY table, which identifies the currency of each country.

The following table shows the contents of the JOB table.

Column Name	Data Type, Default Value, and CHECK Constraints
JOB_CODE (JOBCODE) PRIMARY KEY	VARCHAR(5) NOT NULL CHECK (VALUE > '99999')
JOB_GRADE (JOBGRADE) PRIMARY KEY	SMALLINT NOT NULL CHECK (VALUE BETWEEN 0 AND 6)
JOB_COUNTRY (COUNTRYNAME) PRIMARY KEYFOREIGN KEY - references COUNTRY (COUNTRY)	VARCHAR(15) NOT NULL
JOB_TITLE	VARCHAR(25) NOT NULL
MIN_SALARY (SALARY)	DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (VALUE > 0) CHECK (min_salary < max_salary)
MAX_SALARY (SALARY)	DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (VALUE > 0) CHECK (min_salary < max_salary)
JOB_REQUIREMENT	BLOB segment 400, subtype TEXT Nullable
LANGUAGE_REQ	ARRAY OF [1:5] VARCHAR(15) Nullable


SALES Table

The SALES table contains a record for each sale closed, with PO_NUMBER as the primary key. Foreign keys are CUST_NO referencing the CUSTOMER table and SALES_REP referencing the EMPLOYEE table.

The following table shows the contents of the SALES table.

Column Name	Data Type, Default Value, and CHECK Constraints
PO_NUMBER (PONUMBER) PRIMARY KEY	CHAR(8) NOT NULL CHECK (VALUE STARTING WITH 'V')
CUST_NO (CUSTNO) FOREIGN KEY - references CUSTOMER (CUST_NO)	INTEGER NOT NULL CHECK (VALUE > 1000)
SALES_REP (EMPNO) FOREIGN KEY - references EMPLOYEE (EMP_NO)	SMALLINT Nullable
ORDER_STATUS	VARCHAR(7) NOT NULL DEFAULT 'new'
ORDER_DATE	DATE NOT NULL DEFAULT 'now'
SHIP_DATE	DATE Nullable
DATE_NEEDED	DATE Nullable
PAID	CHAR(1) Nullable DEFAULT 'n'
QTY_ORDERED	INTEGER NOT NULL DEFAULT 1
TOTAL_VALUE	INTEGER NOT NULL
DISCOUNT	FLOAT NOT NULL DEFAULT 0
ITEM_TYPE	(PRODTYPE) VARCHAR(12) NOT NULL DEFAULT 'software' CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))
AGED	Computed by: (ship_date - order_date)
Several checks are performed on the SALES table, among them:

 A sale order must have a status: open, shipped, waiting.

 The ship date must be entered, if order status is "shipped".

 New orders cannot be shipped to customers with "on_hold" status.

The CHECK constraints for this table are:

CHECK (order_status in ("new", "open", "shipped", "waiting"))

CHECK (ship_date >= order_date OR ship_date IS NULL)

CHECK (date_needed > order_date OR date_needed IS NULL)

CHECK (paid in ("y", "n"))

CHECK (qty_ordered >= 1)

CHECK (total_value >= 0)

CHECK (discount >= 0 AND discount <= 1)

CHECK (NOT (order_status = "shipped" AND ship_date IS NULL))

CHECK (NOT (order_status = "shipped" AND
EXISTS (SELECT on_hold FROM customer
WHERE customer.cust_no = sales.cust_no
AND customer.on_hold = "*")))


PROJECT Table

The PROJECT table contains a record for each project, with PROJ_ID as the primary key, and TEAM_LEADER referencing the EMP_NO in the EMPLOYEE table. The PROJ_DEPT_BUDGET column shows the budget for each project and year.

The following table shows the contents of the PROJECT table.

Column Name	Data Type, Default Value, and CHECK Constraints
PROJ_ID (PROJNO) PRIMARY KEY	CHAR(5) NOT NULL CHECK (VALUE = UPPER (VALUE))
PROJ_NAME UNIQUE key	VARCHAR(20) NOT NULL
PROJ_DESC	BLOB segment 800, subtype TEXT Nullable
TEAM_LEADER (EMPNO) FOREIGN KEY - references EMPLOYEE (EMP_NO)	SMALLINT Nullable
PRODUCT (PRODTYPE)	VARCHAR(12) NOT NULL DEFAULT 'software' CHECK (VALUE IN ('software', 'hardware', 'other', 'N/A'))


CUSTOMER Table

The CUSTOMER table contains a record for each customer, with CUST_NO as the primary key, and columns for other information such as address, contact name, and phone number.

The following table shows the contents of the CUSTOMER table.

Column Name	Data Type, Default Value, and CHECK Constraints
CUST_NO (CUSTNO) PRIMARY KEY	INTEGER NOT NULL CHECK (VALUE > 1000)
CUSTOMER	VARCHAR(25) NOT NULL
CONTACT_FIRST (FIRST-NAME)	VARCHAR(15) Nullable
CONTACT_LAST (LASTNAME)	VARCHAR(20) Nullable
PHONE_NO (PHONENUMBER)	VARCHAR(20) Nullable
ADDRESS_LINE1 (ADDRESSLINE)	VARCHAR(30) Nullable
ADDRESS_LINE2 (ADDRESSLINE)	VARCHAR(30) Nullable
CITY	VARCHAR(25) Nullable
STATE_PROVINCE	VARCHAR(15) Nullable
COUNTRY (COUNTRYNAME) FOREIGN KEY - references COUNTRY (COUNTRY)	VARCHAR(15) Nullable
POSTAL_CODE	VARCHAR(12) Nullable
ON_HOLD	CHAR(1) Nullable DEFAULT NULLCHECK (on_hold IS NULL OR on_hold = '*')


EMPLOYEE_PROJECT Table

The following table shows the contents of the EMPLOYEE_PROJECT table.

Column Name	Data Type, Default Value, and CHECK Constraints
EMP_NO (EMPNO) PRIMARY KEY FOREIGN KEY - references EMPLOYEE (EMP_NO)	SMALLINT NOT NULL
PROJ_ID (PROJNO) PRIMARY KEY FOREIGN KEY - references PROJECT (PROJ_ID)	CHAR(5) NOT NULL CHECK (VALUE = UPPER (VALUE))


PROJ_DEPT_BUDGET Table

The following table shows the contents of the PROJ_DEPT_BUDGET table.

Column Name	Data Type, Default Value, and CHECK Constraints
YEAR PRIMARY KEY	INTEGER NOT NULL CHECK (YEAR >= 1993)
PROJ_ID (PROJNO) PRIMARY KEY FOREIGN KEY - references PROJECT (PROJ_ID)	CHAR(5) NOT NULL CHECK (VALUE = UPPER (VALUE))
DEPT_NO (DEPTNO) PRIMARY KEY FOREIGN KEY - references DEPARTMENT (DEPT_NO)	CHAR(3) NOT NULL CHECK (VALUE = '000' OR (VALUE > '0' AND VALUE <= '999') OR VALUE IS NULL)
QUART_HEAD_CNT	ARRAY OF [1:4] INTEGER Nullable
PROJECTED_BUDGET (BUDGET)	DOUBLE PRECISION Nullable DEFAULT 50000 CHECK (VALUE > 10000 AND VALUE <= 2000000)


COUNTRY Table

The following table shows the contents of the COUNTRY table.

Column Name	Data Type, Default Value, and CHECK Constraints
COUNTRY (COUNTRYNAME) PRIMARY KEY	VARCHAR(15) NOT NULL
CURRENCY	VARCHAR(10) NOT NULL


SALARY_HISTORY Table

The SALARY_HISTORY table contains a record for each time an employee's salary changes. It is automatically maintained by the SAVE_SALARY_CHANGE trigger.

The following table shows the contents of the SALARY_HISTORY table.

Column Name	Data Type, Default Value, and CHECK Constraints
EMP_NO (EMPNO) PRIMARY KEY FOREIGN KEY - references EMPLOYEE (EMP_NO)	SMALLINT NOT NULL
CHANGE_DATE PRIMARY KEY	DATE NOT NULL DEFAULT 'NOW'
UPDATER_ID PRIMARY KEY	VARCHAR(20) NOT NULL
OLD_SALARY (SALARY)	DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (VALUE > 0)
PERCENT_CHANGE	DOUBLE PRECISION NOT NULL DEFAULT 0 CHECK (VALUE between -50 and 50)
NEW_SALARY	Computed by: (OLD_SALARY + OLD_SALARY * PERCENT_CHANGE / 100)


Database Objects
Database Objects and Concepts

A database consists of a variety of database objects, such as tables, views, domains, stored procedures, and triggers. Database objects contain all the information about the structure of the database and the data. Because they encapsulate information about the data, database objects are referred to as metadata.

The following sections provide an overview of the InterBase database objects and concepts:

Tables

Columns

Data Types

Domains

Referential Integrity Constraints

Indexes

Views

Stored Procedures

Triggers

Generators

Security


Tables

Relational databases store all their data in tables. A table is a data structure consisting of an unordered set of horizontal rows, each containing the same number of vertical columns. The intersection of an individual row and column is a field that contains a specific piece of information. Much of the power of relational databases comes from defining the relations among the tables.

InterBase stores information about metadata in special tables, called system tables. System tables have predefined columns that store information about the type of metadata in that table. All system tables begin with "RDB$". An example of a system table is RDB$RELATIONS, which stores information about each table in the database.

System tables have the same structure as user-defined tables and are stored in the same database as the user-defined tables. Because the metadata, user-defined tables, and data are all stored in the same database file, each database is a complete unit and can be easily transported between machines.

System tables can be modified like any other database tables. Unless you understand all the interrelationships between the system tables, however, modifying them directly may adversely affect other system tables and disrupt your database.

For a complete discussion of tables, see Working With Tables.

For a complete description of the InterBase system tables and views, see System Tables and Views.


Columns

Creating a table mainly involves defining the columns in the table. The main attributes of a column include:

The name of the column

Data type of the column or the domain on which it is based

Whether or not the column is allowed to be NULL

Optional referential integrity constraints

For a complete discussion on columns, see How To Define Columns.


Data Types

Data is stored in a predefined format called a data type. Data types can be classified into four categories: numeric, character, date, and BLOB. Numeric data types handle everything from integers to double-precision floating point values. Character data types hold strings of text. Date data types are used for storing date and time values.

While numeric, character, and date are standard data types, the BLOB data type deserves special mention.

BLOB Data Types

InterBase supports a binary large object (BLOB) data type, that can hold data of unlimited size. The BLOB is an extension of the standard relational model, which ordinarily provides only for data types of fixed width.

The BLOB data type is analogous to a flat file because BLOB data can be stored in any format (for example, binary or ASCII). A BLOB, however, is not a separate file. BLOB data is stored in the database with all other data. Because BLOB columns often contain large, variable amounts of data, BLOB columns are stored and retrieved in segments.

Conversion of BLOB data to other data types in InterBase is not directly supported, but on some platforms, BLOB filters can translate BLOB data from one BLOB format to another.

For a complete discussion of data types, see Specifying the Data Type.


Domains

In addition to explicitly stating the data type of columns, InterBase allows global column definitions, or domains, upon which column definitions can be based. A domain specifies a data type, and a set of column attributes and constraints. Subsequent table definitions can use the domain to define columns.

For a complete discussion on domains, see Working With Domains.


Referential Integrity Constraints

InterBase allows you to define referential integrity rules for a column, called referential integrity constraints. Integrity constraints govern column-to-table and table-to-table relationships and validate data entries. They are implemented through primary keys, foreign keys, and check constraints. Basically, a primary key is a column (or group of columns) that uniquely identifies a row in a table. A foreign key is a column whose value must match a value of a column in another table. A check constraint limits data entry to a specific range or set of values.

For example, an EMPLOYEE table could be defined to have a foreign key column named DEPT_NO that is defined to match the department number column in a DEPARTMENT table. This would ensure that each employee in the EMPLOYEE table is assigned to an existing department in the DEPARTMENT table.

For more information see, Defining Integrity Constraints.


Indexes

Indexes are mechanisms for improving the speed of data retrieval. An index identifies columns that can be used to retrieve and sort rows efficiently in the table. It provides a means to scan only a specific subset of the rows in a table, improving the speed of data access.

InterBase automatically defines unique indexes for a table's PRIMARY KEY and FOREIGN KEY constraints.

For a complete discussion of indexes, see Working With Indexes.


Views

A view is a virtual table that is not physically stored in the database, but appears exactly like a "real" table. A view can contain data from one or more tables or other views and is used to store often-used queries or query sets in a database.

Views can also provide a limited means of security, because they can provide users access to a subset of available data while hiding other related and sensitive data.

For a complete discussion of views, see Working With Views.


Stored Procedures

A stored procedure is a self-contained program written in InterBase procedure and trigger language, an extension of SQL. Stored procedures are part of a database's metadata. Stored procedures can receive input parameters from and return values to applications and can be executed explicitly from applications, or substituted for a table name in a SELECT statement.

Stored procedures provide:

Modular design: stored procedures can be shared by applications that access the same database, eliminating duplicate code, and reducing the size of applications.

Streamlined maintenance: when a procedure is updated, the changes are automatically reflected in all applications that use it without the need to recompile and relink them. They are compiled and optimized only once for each client.

Improved performance: especially for remote client access. Stored procedures are executed by the server, not the client, which reduces network traffic.

For a complete discussion of stored procedures, see Working With Stored Procedures.


Triggers

A trigger is a self-contained routine associated with a table or view that automatically performs an action when a row in the table or view is inserted, updated, or deleted.

Triggers can provide:

Automatic enforcement of data restrictions to ensure that users enter only valid values into columns.

Reduced application maintenance, because changes to a trigger are automatically reflected in all applications that use the associated table without the need to recompile and relink them.

Automatic logging of changes to tables. An application can keep a running log of changes with a trigger that fires whenever a table is modified.

When a trigger is invoked, it has immediate access to data being stored, modified, or erased. The trigger may also access data in other tables. Using the available data, you can design the trigger to:

Cancel an operation, possibly with an error message.

Set values in the accessed record.

Insert, update, or delete rows in other tables.

For a complete discussion of triggers, see Working With Triggers.


Generators

A generator is a mechanism that creates a unique, sequential number that is automatically inserted into a column by the database when SQL data manipulation operations such as INSERT or UPDATE occur. Generators are typically used to produce unique values that can be inserted into a column that is used as a PRIMARY KEY. Any number of generators can be defined for a database, as long as each generator has a unique name.

For a complete discussion of generators, see Working With Generators.


Security

SQL security is controlled at the table level with access privileges, a list of operations that a user is allowed to perform on a given table or view. The GRANT statement assigns access privileges for a table or view to specified users or procedures. The REVOKE statement removes previously granted access privileges.

For a complete discussion of security, see Planning Security.


Database Design

Framework for Database Design

How to Normalize a Database

How to Choose Indexes

InterBase-specific Design Suggestions


Design Framework

The following steps provide a framework for designing a database:

1.	Collect and analyze the real-world objects that you want to model in your database. Organize the objects into entities and attributes and make a list.

2.	Map the entities and attributes to InterBase tables and columns.

3.	Determine an attribute that will uniquely identify each object.

4.	Develop a set of rules that govern how each table is accessed, populated, and modified.

5.	Establish relationships between the objects (tables and columns).


Collecting and Analyzing Objects

Before designing the database objects--the tables and columns--you need to organize and analyze the real-world data on a conceptual level. There are four primary goals:

Identify the major functions and activities of your organization. For example: hiring employees, shipping products, ordering parts, processing paychecks, and so on.

Identify the objects of those functions and activities. Building a business operation or transaction into a sequence of events will help you identify all of the entities and relationships the operation entails. For example, when you look at a process like "hiring employees," you can immediately identify entities such as the JOB, the EMPLOYEE, and the DEPARTMENT.

Identify the characteristics of those objects. For example, the EMPLOYEE entity might include such information as EMPLOYEE_ID, FIRST_NAME, LAST_NAME, JOB, SALARY, and so on.

Identify certain relationships between the objects. For example, how do the EMPLOYEE, JOB, and DEPARTMENT entities relate to each other? The employee has one job title and belongs to one department, while a single department has many employees and jobs. Simple graphical flow charts help to identify the relationships.


Mapping Entities and Attributes

Based on the requirements that you collect, identify the objects that need to be in the database--the entities and attributes. An entity is a type of person, object, or thing that needs to be described in the database. It may be an object with a physical existence, like a person, a car, or an employee, or it may be an object with a conceptual existence, like a company, a job, or a project. Each entity has properties, called attributes, that describe it. For example, suppose you are designing a database that must contain information about each employee in the company, departmental-level information, information about current projects, and information about customers and sales. The example below shows how to create a list of entities and attributes that organizes the required data.

Entities	Attributes

EMPLOYEE	Employee Number

Last Name

First Name

Department Number

Job Code

Phone Extension

Salary

DEPARTMENT	Department Number

Department Name

Department Head Name

Dept Head Employee Num

Budget

Location

Phone Number

PROJECT	Project ID

Project Name

Project Description

Team Leader

Product

CUSTOMER	Customer Number

Customer Name

Contact Name

Phone Number

Address

SALES	PO Number

Customer Number

Sales Rep

Order Date

Ship Date

Order Status

By listing the entities and associated attributes this way, you can begin to eliminate redundant entries. Do the entities in your list work as tables? Should some columns be moved from one group to another? Does the same attribute appear in several entities? Each attribute should appear only once, and you need to determine which entity is the primary owner of the attribute. For example, DEPARTMENT HEAD NAME should be eliminated because employee names (FIRST NAME and LAST NAME) already exist in the EMPLOYEE entity. DEPARTMENT HEAD EMPLOYEE NUM can then be used to access all of the employee-specific information by referencing EMPLOYEE NUMBER in the EMPLOYEE entity.

Designing Tables

In a relational database, the database object that represents a single entity is a table, which is a two-dimensional matrix of rows and columns. Each column in a table represents an attribute. Each row in the table represents a specific instance of the entity. After you identify the entities and attributes, create the data model, which serves as a logical design framework for creating your InterBase database. The data model maps entities and attributes to InterBase tables and columns, and is a detailed description of the database--the tables, the columns, the properties of the columns, and the relationships between tables and columns.

The example below shows how the EMPLOYEE entity from the entities/attributes list has been converted to a table.

EMP_NO	LAST_NAME	FIRST_NAME	DEPT	JOB_CODE	PHONE_EXT	SALARY
24	Smith	John	100	Eng	4968	64000
48	Carter	Catherine	900	Sales	4967	72500
36	Smith	Jane	600	Admin	4800	37500
Each row in the EMPLOYEE table represents a single employee. EMP_NO, LAST_NAME, FIRST_NAME, DEPT_NO, JOB_CODE, PHONE_EXT, and SALARY are the columns that represent employee attributes. When the table is populated with data, rows are added to the table, and a value is stored at the intersection of each row and column, called a field. In the EMPLOYEE table, "Smith" is a data value that resides in a single field of an employee record.


Determining Unique Attributes

One of the tasks of database design is to provide a way to uniquely identify each occurrence or instance of an entity so that the system can retrieve any single row in a table. The values specified in the table's primary key distinguish the rows from each other. A PRIMARY KEY or UNIQUE constraint ensures that values entered into the column or set of columns are unique in each row. If you try to insert a value in a PRIMARY KEY or UNIQUE column that already exists in another row of the same column, InterBase prevents the operation and returns an error.

For example, in the EMPLOYEE table, EMP_NO is a unique attribute that can be used to identify each employee in the database, so it is the primary key. When you choose a value as a primary key, determine whether it is inherently unique. For example, no two social security numbers or driver's license numbers are ever the same. Conversely, you should not choose a name column as a unique identifier due to the probability of duplicate values. If no single column has this property of being inherently unique, then define the primary key as a composite of two or more columns which, when taken together, are unique.

A unique key is different from a primary key in that a unique key is not the primary identifier for the row, and is not typically referenced by a foreign key in another table. The main purpose of a unique key is to force a unique value to be entered into the column. You can have only one primary key defined for a table, but any number of unique keys.


Developing a Set of Rules

When designing a table, you need to develop a set of rules for each table and column that establishes and enforces data integrity. These rules include:

Selecting a data type.

Choosing international character sets.

Specifying domains.

Setting default values and NULL status.

Defining constraints.


Selecting a Data Type

Once you have chosen a given attribute as a column in the table, you can choose a data type for the attribute. The data type defines the set of valid data that the column can contain. The data type also determines which operations can be performed on the data, and defines the disk space requirements for each data item.

The general categories of SQL data types include:

Character data types.

Whole number (integer) data types.

Fixed and floating decimal data types.

A DATE data type to represent date and time.

A BLOB data type to represent unstructured binary data, such as graphics and digitized voice.

For a complete discussion of data types, see Specifying the Data Type.


Choosing International Character Sets

When you create the database, you can specify a default character set. A default character set determines:

What characters can be used in CHAR, VARCHAR, and BLOB text columns.

The default collation order that is used in sorting a column.

The collation order determines the order in which values are sorted. The COLLATE clause of CREATE TABLE allows users to specify a particular collation order for columns defined as CHAR and VARCHAR text data types. You must choose a collation order that is supported for the column's given character set. The collation order set at the column level overrides a collation order set at the domain level.

Choosing a default character set is primarily intended for users who are interested in providing a database for international use. For example, the following statement creates a database that uses the ISO8859_1 character set, typically used to support European languages:

CREATE DATABASE "employee.gdb"
DEFAULT CHARACTER SET ISO8859_1;

You can override the database default character set by creating a different character set for a column when specifying the data type. The data type specification for a CHAR, VARCHAR, or BLOB text column definition can include a CHARACTER SET clause to specify a particular character set for a column. If you do not specify a character set, the column assumes the default database character set. If the database default character set is subsequently changed, all columns defined after the change have the new character set, but existing columns are not affected.

If you do not specify a default character set at the time the database is created, the character set defaults to NONE. This means that there is no character set assumption for the columns; data is stored and retrieved just as it was originally entered. You can load any character set into a column defined with NONE, but you cannot load that same data into another column that has been defined with a different character set. No transliteration will be performed between the source and the destination character sets.


Specifying Domains

When several tables in the database contain columns with the same definitions and data types, you can create domain definitions and store them in the database. Users who create tables can then reference the domain definition to define column attributes locally.

For a complete discussion on domains, see Working With Domains.

For instructions on how to define domain-based columns, see Defining Domain-based Columns.


Setting Default Values and NULL Status

You can set an optional default value that is automatically entered into a column when you do not specify an explicit value. Defaults can save data entry time and prevent data entry errors. For example, a possible default for a DATE column could be today's date, or in a Y/N flag column for saving changes, "Y" could be the default. Column-level defaults override defaults set at the domain level.

Assign a NULL status to insert a NULL in the column if the user does not enter a value. Assign NOT NULL to force the user to enter a value, or to define a default value for the column. NOT NULL must be defined for PRIMARY KEY and UNIQUE key columns.


Defining Constraints

Integrity constraints are rules that govern column-to-table and table-to-table relationships, and validate data entries. They span all transactions that access the database and are automatically maintained by the system. Integrity constraints can be applied to an entire table or to an individual column. A PRIMARY KEY or UNIQUE constraint guarantees that no two values in a column or set of columns will ever be the same.

Data values that uniquely identify rows (a primary key) in one table can also appear in other tables. A foreign key is a column or set of columns in one table that contain values that match a primary key in another table.

CHECK Constraints

Along with preventing the duplication of values using UNIQUE and PRIMARY KEY constraints, you can specify another type of data entry validation. A CHECK constraint places a condition or requirement on the data values in a column at the time the data is entered. The CHECK constraint enforces a search condition that must be true in order to insert into or update the table or column.


Establishing Relationships Between Objects

The relationship between tables and columns in the database must be defined in the design. For example, how are employees and departments related? An employee can have only one department (a one-to-one relationship), but a department has many employees (a one-to-many relationship). How are projects and employees related? An employee can be working on more than one project, and a project can include several employees (a many-to-many relationship). Each of these different types of relationships has to be modeled in the database.

The relational model represents one-to-many relationships with primary key/foreign key pairings. Refer to the following two tables. A project can include many employees, so to avoid duplication of employee data, the PROJECT table can reference employee information with a foreign key. TEAM_LEADER is a foreign key referencing the primary key, EMP_NO, in the EMPLOYEE table.

PROJ_ID	TEAM_LEADER	PROJ_NAME	PROJ_DESC	PRODUCT
DGPII	44	Automap	blob data	hardware
VBASE	47	Video database	blob data	software
HWRII	24	Translator upgrade	blob data	software
EMP_NO	LAST_NAME	FIRST_NAME	DEPT	JOB_CODE	PHONE_EXT	SALARY
24	Smith	John	100	Eng	4968	64000
48	Carter	Catherine	900	Sales	4967	72500
36	Smith	Jane	600	Admin	4800	37500
Enforcing Referential Integrity

The primary reason for defining foreign keys is to ensure that the integrity of the data is maintained when more than one table references the same data--rows in one table must always have corresponding rows in the referencing table. InterBase enforces referential integrity in the following ways:

Before a foreign key can be added, the unique or primary keys that the foreign key references must already be defined.

If information is changed in one place, it must be changed in every other place that it appears. For example, to change a value in the EMP_NO column of the EMPLOYEE table (the primary key), that value must also be updated in the TEAM_LEADER column of the PROJECT table (the foreign key).

If a user could delete a row containing a primary key in one table, the meaning of any rows in another table that contain that value as a foreign key would be lost. To preserve referential integrity, InterBase prevents anyone from deleting values from a primary key that have matching foreign keys in another referencing table. The user must first delete all foreign key rows before deleting the primary key to which they refer.

InterBase also prevents users from adding a value in a column defined as a foreign key that does not reference an existing primary key value. For example, to change a value in the TEAM_LEADER column of the PROJECT table, that value must first be updated in the EMP_NO column of the EMPLOYEE table.


How to Normalize a Database

After your tables, columns, and keys are defined, look at the design as a whole and analyze it using normalization guidelines in order to find logical errors. As mentioned in the overview, normalization involves breaking down larger tables into smaller ones in order to group data together that is naturally related.

Note:	A detailed explanation of the normal forms are out of the scope of this document. There are many excellent books on the subject on the market.

When a database is designed using proper normalization methods, data related to other data does not need to be stored in more than one place--if the relationship is properly specified. The advantages of storing the data in one place are:

The data is easier to update or delete.

When each data item is stored in one location and accessed by reference, the possibility for error due to the existence of duplicates is reduced.

Because the data is stored only once, the possibility for introducing inconsistent data is reduced.

In general, the normalization process includes:

Eliminating repeating groups.

Removing partially-dependent columns.

Removing transitively-dependent columns.

When to Break the Rules

You should try to correct any normalization violations, or else make a conscious decision to ignore them in the interest of ease of use or performance. Just be sure that you understand the design trade-offs that you are making, and document your reasons. It may take several iterations to reach a design that is a desirable compromise between purity and reality, but this is the heart of the design process.

For example, suppose you always want data about dependents every time you look up an employee, so you decide to include DEP1_NAME, DEP1_BIRTHDATE, and so on for DEP1 through DEP30, in the EMPLOYEE table. Generally speaking, that is terrible design, but the requirements of your application are more important than the abstract purity of your design. In this case, if you wanted to compute the average age of a given employee's dependents, you would have to explicitly add field values together, rather than asking for a simple average. If you wanted to find all employees with a dependent named "Jennifer," you would have to test 30 fields for each employee instead of one. If those are not operations that you intend to perform, then go ahead and break the rules. If the efficiency attracts you less than the simplicity, you might consider defining a view that combines records from employees with records from a separate DEPENDENTS table.

While you are normalizing your data, remember that InterBase offers direct support for array columns, so if your data includes, for example, hourly temperatures for twenty cities for a year, you could define a table with a character column that contains the city name, and a 24 by 366 matrix to hold all of the temperature data for one city for one year. This would result in a table containing 20 rows (one for each city) and two columns, one NAME column and one TEMP_ARRAY column. A normalized version of that record might have 366 rows per city, each of which would hold a city name, a Julian date, and 24 columns to hold the hourly temperatures.


Eliminating Repeating Groups

When a field in a given row contains more than one value for each occurrence of the primary key, then that group of data items is called a repeating group. This is a violation of the first normal form, which does not allow multi-valued attributes.

Refer to the DEPARTMENT table. For any occurrence of a given primary key, if a column can have more than one value, then this set of values is a repeating group. Therefore, the first row, where DEPT_NO = "100," contains a repeating group in the DEPT_LOCATIONS column.

DEPT_NO	DEPARTMENT	HEAD_DEPT	BUDGET	DEPT_LOCATIONS
100	Sales	000	1000000	Monterey, Santa Cruz, Salinas
600	Engineering	120	1100000	San Francisco
900	Finance	000	400000	Monterey
In the next example, even if you change the attribute to represent only one location, for every occurrence of the primary key "100," all of the columns contain repeating information except for DEPT_LOCATION, so this is still a repeating group.

DEPT_NO	DEPARTMENT	HEAD_DEPT	BUDGET	DEPT_LOCATION
100	Sales	000	1000000	Monterey
100	Sales	000	1000000	Santa Cruz
600	Engineering	120	1100000	San Francisco
100	Sales	000	1000000	Salinas
To normalize this table, we could eliminate the DEPT_LOCATION attribute from the DEPARTMENT table, and create another table called DEPT_LOCATIONS. We could then create a primary key that is a combination of DEPT_NO and DEPT_LOCATION. Now a distinct row exists for each location of the department, and we have eliminated the repeating groups.

DEPT_NO	DEPT_LOCATION

100	Monterey

100	Santa Cruz

600	San Francisco

100	Salinas


Removing Partially-dependent Columns

Another important step in the normalization process is to remove any non-key columns that are dependent on only part of a composite key. Such columns are said to have a partial key dependency. Non-key columns provide information about the subject, but do not uniquely define it.

For example, suppose you wanted to locate an employee by project, and you created the PROJECT table with a composite primary key of EMP_NO and PROJ_ID.

EMP_NO	PROJ_ID	LAST_NAME	PROJ_NAME	PROJ_DESC	PRODUCT
44	DGPII	Smith	Automap	blob data	hardware
47	VBASE	Jenner	Video database	blob data	software
24	HWRII	Stevens	Translator upgrade	blob data	software
The problem with this table is that PROJ_NAME, PROJ_DESC, and PRODUCT are attributes of PROJ_ID, but not EMP_NO, and are therefore only partially dependent on the EMP_NO/PROJ_ID primary key. This is also true for LAST_NAME because it is an attribute of EMP_NO, but does not relate to PROJ_ID. To normalize this table, we would remove the EMP_NO and LAST_NAME columns from the PROJECT table, and create another table called EMPLOYEE_PROJECT that has EMP_NO and PROJ_ID as a composite primary key. Now a unique row exists for every project that an employee is assigned to.


Removing Transitively-dependent Columns

The third step in the normalization process is to remove any non-key columns that depend upon other non-key columns. Each non-key column must be a fact about the primary key column. For example, suppose we added TEAM_LEADER_ID and PHONE_EXT to the PROJECT table, and made PROJ_ID the primary key. PHONE_EXT is a fact about TEAM_LEADER_ID, a non-key column, not about PROJ_ID, the primary key column.

PROJ_ID	TEAM_LEADER_ID	PHONE_EXT	PROJ_NAME	PROJ_DESC	PRODUCT
DGPII	44	4929	Automap	blob data	hardware
VBASE	47	4967	Video database	blob data	software
HWRII	24	4668	Translator upgrade	blob data	software
To normalize this table, we would remove PHONE_EXT, change TEAM_LEADER_ID to TEAM_LEADER, and make TEAM_LEADER a foreign key referencing EMP_NO in the EMPLOYEE table.

PROJ_ID	TEAM_LEADER	PROJ_NAME	PROJ_DESC	PRODUCT
DGPII	44	Automap	blob data	hardware
VBASE	47	Video database	blob data	software
HWRII	24	Translator upgrade	blob data	software
EMP_NO	LAST_NAME	FIRST_NAME	DEPT_NO	JOB_CODE	PHONE_EXT	SALARY
24	Smith	John	100	Eng	4968	64000
48	Carter	Catherine	900	Sales	4967	72500
36	Smith	Jane	600	Admin	4800	37500


How to Choose Indexes

Once you have your design, you need to consider what indexes are necessary. The basic trade-off with indexes is that more distinct indexes make retrieval by specific criteria faster, but updating and storage slower. One optimization is to avoid creating several indexes on the same column. For example, if you sometimes retrieve employees based on name, department, badge number, or department name, you should define one index for each of these columns. If a query includes more than one column value to retrieve, InterBase will use more than one index to qualify records. In contrast, defining indexes for every permutation of those three columns will actually slow both retrieval and update operations.

When you are testing your design to find the optimum combination of indexes, remember that the size of the tables affects the retrieval performance significantly. If you expect to have tables with 10,000 to 100,000 records each, do not run tests with only 10 to 100 records.

Another factor that affects index and data retrieval times is page size. By increasing the page size, you can store more records on each page, thus reducing the number of pages used by indexes. If any of your indexes are more than 4 levels deep, you should consider increasing the page size. If indexes on volatile data (data that is regularly deleted and restored, or data that has index key values that change frequently) are less than 3 levels deep, you should consider reducing your page size. In general, you should use a page size larger than your largest record, although InterBase's data compression will generally shrink records that contain lots of string data, or lots of numeric values that are 0 or NULL. If your records have those characteristics, you can probably store records on pages which are 20% smaller than the full record size. On the other hand, if your records are not compressible, you should add 5% to the actual record size when comparing it to the page size.


InterBase-specific Design Suggestions

Increasing Cache Size

When InterBase reads a page from the database onto disk, it stores that page in its cache, which is a set of buffers that are reserved for holding database pages. Ordinarily, the default cache size of 75 buffers is adequate. If your application includes joins of 5 or more tables, InterBase automatically increases the size of the cache. If your application is well localized, that is, it uses the same small part of the database repeatedly, you may want to consider increasing the cache size so that you never have to release one page from cache to make room for another. Generally, increasing the cache size beyond 200 pages does not improve performance unless you are using a multi-client server.

Creating a Multi-file, Distributed Database

If you feel that your application performance is limited by disk bandwidth, you might consider creating a multi-file database and distributing it across several disks. Multi-file databases were designed to avoid limiting databases to the size of a disk on systems that do not support multi-disk files.


Working With Databases

How to Create Databases

How to Alter Databases

How to Drop Databases

How to Extract Metadata From Existing Databases

Working With Domains

Working With Tables

Working With Indexes

Working With Views

Working With Stored Procedures

Working With Triggers

Working With Generators

Planning Security


How to Create Databases

To create a database and its components, InterBase uses an implementation of SQL which conforms to the ANSI SQL-89 entry-level standard and follows SQL-92 and SQL3 beta specifications for advanced features.

Building a database involves defining the data. For this purpose InterBase provides a set of statements called the Data Definition Language (DDL).

An InterBase database is a single file comprising all the metadata and data in the database. To create a new database for the Local InterBase Server, use Windows ISQL. Create a database in ISQL with an interactive command or with the CREATE DATABASE statement in an ISQL script file.

Prerequisites

Before creating the database, you should know:

Where to create the database. Users who create databases need to know only the logical names of the available devices in order to allocate database storage. Only the system administrator needs to be concerned about physical storage (disks, disk partitions, operating system files).

The tables that the database will contain.

The record size of each table, which affects what database page size you choose. A record that is too large to fit on a single page requires more than one page fetch to read or write to it, so access could be faster if you increase the page size.

How large you expect the database to grow. The number of records also affects the page size because the number of pages affects the depth of the index tree. Larger page size means fewer total pages. InterBase operates more efficiently with a shallow index tree.

The number of users that will be accessing the database.

Although you can create, alter, and drop a database interactively, it is preferable to use a data definition file because it provides a record of the structure of the database. It is easier to modify a source file than it is to start over by retyping interactive SQL statements.

Using CREATE DATABASE

Creating a Single-file Database

Creating a Multi-file Database

Specifying User Name and Password

Specifying Database Page Size

Specifying the Default Character Set


Using a Data Definition File

A data definition file may include statements to create, alter, or drop a database, or any other SQL statements. To issue SQL statements through a data definition file, create an ISQL script and process it using Windows ISQL.


Using CREATE DATABASE

CREATE DATABASE establishes a new database and populates its system tables, or metadata, which are the tables that describe the internal structure of the database. CREATE DATABASE must occur before creating database tables, views, and indexes.

CREATE DATABASE optionally allows you to do the following:

Specify a user name and a password

Change the default page size of the new database

Specify a default character set for the database

Add secondary files to expand the database

CREATE DATABASE must be the first statement in the data definition file. You cannot create a database directly from the ISQL command line.

In DSQL, CREATE DATABASE can only be executed with EXECUTE IMMEDIATE. The database handle and transaction name, if present, must be initialized to zero prior to use.

The syntax for CREATE DATABASE is:

CREATE {DATABASE | SCHEMA} "<filespec>"
[USER "username" [PASSWORD "password"]]
[PAGE_SIZE [=] int]
[LENGTH [=] int [PAGE[S]]]
[DEFAULT CHARACTER SET charset]
[<secondary_file>];

<secondary_file> = FILE "<filespec>" [<fileinfo>] [<secondary_file>]

<fileinfo> = LENGTH [=] int [PAGE[S]] | STARTING [AT [PAGE]] int [<fileinfo>]

The complete syntax of CREATE DATABASE is in the online SQL Reference.


Creating a Single-file Database

Although there are many optional parameters, CREATE DATABASE requires only one parameter, "<filespec>", which is the new database file specification. The file specification contains the device name, path name, and database name.

By default, a database is created as a single file, called the primary file. The following example creates a single-file database, named employee.gdb, in the current directory.

CREATE DATABASE "employee.gdb";

Specifying File Size for a Single-file Database

You can optionally specify a file length, in pages, for the primary file. For example, the following statement creates a database that is stored in one 10,000-page long file:

CREATE DATABASE "employee.gdb" LENGTH 10000;

If the database grows larger than the specified file length, InterBase extends the primary file beyond the LENGTH limit until the disk space runs out. To avoid this, you can store a database in more than one file, called a secondary file.

Note:	Use LENGTH for the primary file only if defining a secondary file in the same statement.


Creating a Multi-file Database

A multi-file database consists of a primary file and one or more secondary files. You can create one or more secondary files to be used for overflow purposes only; you cannot specify what information goes into each file because InterBase handles this automatically. Each secondary file is typically assigned to a different disk than that of the main database. When the primary file fills up, InterBase allocates one of the secondary files that was created. When that secondary file fills up, another secondary file is allocated, and so on, until all of the secondary file allocations run out.

 Whenever possible, the database should be created locally; create the database on the same machine where you are running ISQL. If the database is created locally, secondary file names can include a full file specification, including both host or node names, and a directory path to the location of the database file. If the database is created on a remote server, secondary file specifications cannot include a node name, as all secondary files must reside on the same node.

Specifying File Size of a Secondary File

Unlike primary files, when you define a secondary file, you must declare either a file length in pages, or a starting page number. The LENGTH parameter specifies a database file size in pages.

If you choose to describe page ranges in terms of length, list the files in the order in which they should be filled. The following example creates a database that is stored in four 10,000-page files, Starting with page 10,001, the files are filled in the order employee.gdb, employee.gd1, employee.gd2, and employee.gd3.

CREATE DATABASE "employee.gdb"

FILE "employee.gd1" STARTING AT PAGE 10001

LENGTH 10000 PAGES

FILE "employee.gd2"

LENGTH 10000 PAGES

FILE "employee.gd3";
LENGTH 10000 PAGES

Note:	Because file-naming conventions are platform-specific, for the sake of simplicity, none of the examples provided include the device and path name portions of the file specification.

When the last secondary file fills up, InterBase automatically extends the file beyond the LENGTH limit until its disk space runs out. You can either specify secondary files when the database is defined, or add them later, as they become necessary, using ALTER DATABASE. Defining secondary files when a database is created immediately reserves disk space for the database.

Specifying the Starting Page Number of a Secondary File

If you do not declare a length for a secondary file, then you must specify a starting page number. STARTING AT PAGE specifies the beginning page number for a secondary file.

The primary file specification in a multi-file database does not need to include a length, but secondary file specifications must then include a starting page number. You can specify a combination of length and starting page numbers for secondary files.

InterBase overrides a secondary file length that is inconsistent with the starting page number. In the next example, the primary file is 10,000 pages long, but the first secondary file starts at page 5,000:

CREATE DATABASE "employee.gdb" LENGTH 10000

FILE "employee.gd1" STARTING AT PAGE 5000

LENGTH 10000 PAGES

FILE "employee.gd2"

LENGTH 10000 PAGES

FILE "employee.gd3";

InterBase generates a primary file that is 10,000 pages long, starting the first secondary file at page 10,001.


Specifying User Name and Password

If provided, the user name and password are checked against valid user name and password combinations in the security database on the server where the database will reside. Passwords are restricted to 8 characters in length.

Important:	Windows client applications must create their databases on a remote server. For these remote connections, the user name and password are not optional. Windows clients must provide the USER and PASSWORD options with CREATE DATABASE before connecting to a remote server.

The following statement creates a database with a user name and password:

CREATE DATABASE "employee.gdb" USER "SALES" PASSWORD "mycode";


Specifying Database Page Size

You can optionally override the default page size of 1024 bytes for database pages by specifying a different PAGE_SIZE. PAGE_SIZE can be 1024, 2048, 4096, or 8192. The next statement creates a single-file database with a page size of 2048 bytes:

CREATE DATABASE "employee.gdb" PAGE_SIZE 2048;

When to Increase Page Size

Increasing page size can improve performance for several reasons:

Indexes work faster because the depth of the index is kept to a minimum.

Keeping large rows on a single page is more efficient. (A row that is too large to fit on a single page requires more than one page fetch to read or write to it.)

BLOB data is stored and retrieved more efficiently when it fits on a single page. If an application typically stores large BLOB columns (between 1K and 2K), a page size of 2048 bytes is preferable to the default (1024).

If most transactions involve only a few rows of data, a smaller page size may be appropriate, since less data needs to be passed back and forth and less memory is used by the disk cache.

Changing Page Size for an Existing Database

To change a page size of an existing database, follow these steps:

1.	Back up the database.

2.	Restore the database using the PAGE_SIZE option to specify a new page size.


Specifying the Default Character Set

DEFAULT CHARACTER SET allows you to optionally set the default character set for the database. The character set determines:

What characters can be used in CHAR, VARCHAR, and BLOB text columns.

The default collation order that is used in sorting a column.

Choosing a default character set is useful for all databases, even those where international use is not an issue. Choice of character set determines if transliteration among character sets is possible. For example, the following statement creates a database that uses the ISO8859_1 character set, typically used in Europe to support European languages:

CREATE DATABASE "employee.gdb"
DEFAULT CHARACTER SET "ISO8859_1";

Using CHARACTER SET NONE

If you do not specify a default character set, the character set defaults to NONE. Using CHARACTER SET NONE means that there is no character set assumption for columns; data is stored and retrieved just as you originally entered it. You can load any character set into a column defined with NONE, but you cannot load that same data into another column that has been defined with a different character set. No transliteration will be performed between the source and destination character sets, so in most cases, errors will occur during the attempted assignment.

For example:

CREATE TABLE MYDATA (PART_NUMBER CHARACTER(30) CHARACTER SET NONE);

SET NAMES LATIN1;

INSERT INTO MYDATA (PART_NUMBER) VALUES ("à");

SET NAMES DOS437;

SELECT * FROM MYDATA;

The data ("à") is returned just as it was entered, without the à being transliterated from the input character (LATIN1) to the output character (DOS437). If the column had been set to anything other than NONE, the transliteration would have occurred.


How to Alter Databases

A database can be altered by its creator, the SYSDBA user, and any users with operating system root privileges.

ALTER DATABASE requires exclusive access to the database.

The syntax for ALTER DATABASE is:

ALTER {DATABASE | SCHEMA}
ADD <add_clause>;

<add_clause> =
FILE "<filespec>" <fileinfo> [<add_clause>]

<fileinfo> = LENGTH [=] int [PAGE[S]] | STARTING [AT [PAGE]] int [<fileinfo>]

The complete syntax of ALTER DATABASE is in the online SQL Reference.

Example

Use ALTER DATABASE to add one or more secondary files to an existing database. Secondary files are useful for controlling the growth and location of a database. They permit database files to be spread across storage devices, but must remain on the same node as the primary database file.

You must specify a range of pages for each file either by providing the number of pages in each file, or by providing the starting page number for the file. The following statement adds two secondary files to the currently connected database:

ALTER DATABASE

ADD FILE "employee.gd1"

STARTING AT PAGE 10001

LENGTH 10000

ADD FILE "employee.gd2"

LENGTH 10000;


How to Drop Databases

DROP DATABASE is the command that deletes the database currently connected to, including any associated shadow and log files. Dropping a database deletes any data it contains. A database can be dropped by its creator, the SYSDBA user, and any users with operating system root privileges.

The following statement deletes the current database:

DROP DATABASE;


How to Extract Metadata From Existing Databases

ISQL enables you to extract data definition statements from a database and store them in an output file. All keywords and objects are extracted into the file in uppercase.

The output file enables users to:

Examine the current state of a database's system tables before planning alterations. This is especially useful when the database has changed significantly since its creation.

Create a database with schema definitions that are identical to the extracted database.

Make changes to the database, or create a new database source file with a text editor.


Working With Domains

How to Create Domains

How to Alter Domains

How to Drop Domains


How to Create Domains

When you create a table, you can use a global column definition, called a domain, to define a column locally. Before defining a column that references a domain, you must first create the domain definition in the database with CREATE DOMAIN. CREATE DOMAIN acts as a template for defining columns in subsequent CREATE TABLE and ALTER TABLE statements.

Domains are useful when many tables in a database contain identical column definitions. Columns based on a domain definition inherit all characteristics of the domain; some of these attributes can be overridden by local column definitions.

Note:	You cannot apply referential integrity constraints to a domain.

Using CREATE DOMAIN

The syntax for CREATE DOMAIN is:

CREATE DOMAIN domain [AS] <datatype>
[DEFAULT {literal | NULL | USER}]
[NOT NULL] [CHECK (<dom_search_condition>)]
[COLLATE collation];

The complete syntax of CREATE DOMAIN is in the online SQL Reference.

When you create a domain in the database, you must specify a unique name for the domain, and define the various attributes and constraints of the column definition. These attributes include:

Data Type

Collation Order

Default Values

CHECK Constraints


Domain Data Type

The data type is the only required attribute that must be set for the domain--all other attributes are optional. The data type defines the set of valid data that the column can contain. The data type also determines the set of allowable operations that can be performed on the data, and defines the disk space requirements for each data item.

The syntax for specifying the data type is:

<datatype> = {
{SMALLINT | INTEGER | FLOAT | DOUBLE PRECISION} [<array_dim>]
| {DECIMAL | NUMERIC} [(precision [, scale])] [<array_dim>]
| DATE [<array_dim>]
| {CHAR | CHARACTER | CHARACTER VARYING | VARCHAR}
[(int)] [<array_dim>] [CHARACTER SET charname]
| {NCHAR | NATIONAL CHARACTER | NATIONAL CHAR}
[VARYING] [(int)] [<array_dim>]
| BLOB [SUB_TYPE {int | subtype_name}] [SEGMENT SIZE int]
[CHARACTER SET charname]
| BLOB [(seglen [, subtype])]
}

<datatype> is the SQL data type for any column based on a domain. You cannot override the domain data type with a local column definition.

The general categories of SQL data types include:

Character data types.

Integer data types.

Decimal data types, both fixed and floating.

A DATE data type to represent date and time. InterBase does not directly support the SQL DATE, TIME, and TIMESTAMP data types.

A BLOB data type to represent unstructured binary data, such as graphics and digitized voice.

InterBase supports the following data types

Name: BLOB	Size: Variable

Range/Precision: None

Description: Binary large object. Stores large data, such as graphics, text, and digitized voice. Basic structural unit: segment. BLOB subtype describes BLOB contents.

Name: CHAR(n)	Size: n characters

Range/Precision: 1 to 32767 bytes. Character set character size determines the maximum number of characters that can fit in 32K.

Description: Fixed length CHAR or text string type. Alternate keyword: CHARACTER

Name: DATE	Size: 64 bits

Range/Precision: 1 Jan 100 to 11 Jan 5941

Description: Also includes time information.

Name: DECIMAL (precision, scale)	Size: variable

Range/Precision: precision = 1 to 15. Specifies at least precision digits of precision to store. scale = 1 to 15. Specifies number of decimal places for storage. Must be less than or equal to precision.

Description: Number with a decimal point scale digits from the right. For example, DECIMAL(10, 3) holds numbers accurately in the following format:

ppppppp.sss

Name: DOUBLE PRECISION	Size: 64 bits

Range/Precision: 1.7 X 10-308 to 1.7 X 10308

Description: Scientific: 15 digits of precision.

Note:	Actual size of DOUBLE is platform dependent. Most platforms support the 64 bit size.

Name: FLOAT	Size: 32 bits

Range/Precision: 3.4 X 10-38 to 3.4 X 1038

Description: Single precision: 7 digits of precision.

Name: INTEGER	Size: 32 bits

Range/Precision: 2,147,483,648 to 2,147,483,648

Description: Signed long (longword).

Name: NUMERIC (precision, scale)	Size: variable

Range/Precision: precision = 1 to 15. Specifies exactly precision digits of precision to store. scale = 1 to 15. Specifies number of decimal places for storage. Must be less than or equal to precision.

Description: Number with a decimal point scale digits from the right. For example, NUMERIC(10,3) holds numbers accurately in the following format:

ppppppp.sss

Name: SMALLINT	Size: 16 bits

Range/Precision: -32768 to 32767

Description: Signed short (word).

Name: VARCHAR (n)	Size: n characters

Range/Precision: 1 to 32767 bytes. Character set character size determines the maximum number of characters that can fit in 32K.

Description: Variable length CHAR or text string type. Alternate keywords: VARYING CHAR, VARYING CHARACTER

The next statement creates a BLOB domain with a text subtype that has an assigned character set:

CREATE DOMAIN DESCRIPT AS BLOB SUB_TYPE TEXT SEGMENT SIZE 80
CHARACTER SET SJIS;


Domain Collation Order

The COLLATE clause of CREATE DOMAIN allows you to specify a particular collation order for columns defined as CHAR or VARCHAR text data types. You must choose a collation order that is supported for the column's given character set. The character set is either the default character set for the entire database, or you can specify a different set in the CHARACTER SET clause of the data type definition. The collation order set at the column level overrides a collation order set at the domain level.

In the following statement, the domain, TITLE, overrides the database default character set, specifying a DOS437 character set with a PDOX_INTL collation order:

CREATE DOMAIN TITLE AS
CHAR(50) CHARACTER SET DOS437 COLLATE PDOX_INTL;


Domain Default Values

You can set an optional default value that is automatically entered into a column if you do not specify an explicit value. Defaults set at the column level with CREATE TABLE or ALTER TABLE override defaults set at the domain level. Defaults can save data entry time and prevent data entry errors. For example, a possible default for a DATE column could be today's date, or in a (Y/N) flag column for saving changes, "Y" could be the default.

Default values can be:

literal - The default value is a user-specified string, numeric value, or date value.

NULL - If the user does not enter a value, a NULL value is entered into the column.

USER - The default is the name of the current user. If your operating system supports the use of 8 or 16-bit characters in user names, then the column into which USER will be stored must be defined using a compatible character set.

In the following example, the first statement creates a domain with USER named as the default. The next statement creates a table that includes a column, ENTERED_BY, based on the USERNAME domain.

CREATE DOMAIN USERNAME AS VARCHAR(20)
DEFAULT USER;

CREATE TABLE ORDERS (ORDER_DATE DATE, ENTERED_BY USERNAME, ORDER_AMT DECIMAL(8,2));

INSERT INTO ORDERS (ORDER_DATE, ORDER_AMT)
VALUES ("1-MAY-93", 512.36);

The INSERT statement does not include a value for the ENTERED_BY column, so InterBase automatically inserts the user name of the current user, JSMITH:

SELECT * FROM ORDERS;

1-MAY-93 JSMITH 512.36

Specifying NOT NULL

You can optionally specify NOT NULL to force the user to enter a value. If you do not specify NOT NULL, then NULL values are allowed for any column that references this domain. NOT NULL specified on the domain level cannot be overridden by a local column definition.

Note:	If you have already specified NULL as a default value, be sure not to create contradictory constraints by also assigning NOT NULL to the domain, as in the following example:

CREATE DOMAIN DOM1 INTEGER DEFAULT NULL, NOT NULL;


Domain CHECK Constraints

You can specify a condition or requirement on a data value at the time the data is entered by applying a CHECK constraint to a column. The CHECK constraint in a domain definition sets a search condition (<dom_search_condition>) that must be true before data can be entered into columns based on the domain.

The syntax of the search condition is:

<dom_search_condition> = {
VALUE <operator> <val>
| VALUE [NOT] BETWEEN <val> AND <val>
| VALUE [NOT] LIKE <val> [ESCAPE <val>]
| VALUE [NOT] IN (<val> [, <val> ...])
| VALUE IS [NOT] NULL
| VALUE [NOT] CONTAINING <val>
| VALUE [NOT] STARTING [WITH] <val>
| (<dom_search_condition>)
| NOT <dom_search_condition>
| <dom_search_condition> OR <dom_search_condition>
| <dom_search_condition> AND <dom_search_condition>
}

<operator> = {= | < | > | <= | >= | !< | !> | <> | !=}

The following restrictions apply to CHECK constraints:

A CHECK constraint cannot reference any other domain or column name.

A domain can have only one CHECK constraint.

You cannot override the domain's CHECK constraint with a local CHECK constraint. A column based on a domain can add additional CHECK constraints to the local column definition.

Using the VALUE Keyword

VALUE defines the set of values that is valid for the domain. VALUE is a place-holder for the name of a column that will eventually be based on the domain. The search condition can verify whether the value entered falls within a certain range, or match it to any one value in a list of values.

Note:	If NULL values are allowed, they must be included in the CHECK constraint, as in the following example:

CHECK ((VALUE IS NULL) OR (VALUE > 1000));

The next statement creates a domain where value must be > 1,000:

CREATE DOMAIN CUSTNO
AS INTEGER
CHECK (VALUE > 1000);

The following statement creates a domain that must have a positive value greater than 1,000, with a default value of 9,999.

CREATE DOMAIN CUSTNO

AS INTEGER
DEFAULT 9999
CHECK (VALUE > 1000);

The next statement limits the values entered in the domain to four specific values:

CREATE DOMAIN PRODTYPE

AS VARCHAR(12)
CHECK (VALUE IN ("software", "hardware", "other", "N/A"));

When a problem cannot be solved using comparisons, you can instruct the system to search for a specific pattern in a character column. For example, the next search condition allows only cities in California to be entered into columns that are based on the CALIFORNIA domain:

CREATE DOMAIN CALIFORNIA
AS VARCHAR(25)
CHECK (VALUE LIKE "%, CA");


How to Alter Domains

ALTER DOMAIN changes any aspect of an existing domain except its data type and NOT NULL setting. Changes that you make to a domain definition affect all column definitions based on the domain that have not been overridden at the table level.

Note:	To change a data type or NOT NULL setting of a domain, drop the domain and recreate it with the desired combination of features.

A domain can be altered by its creator, the SYSDBA user, and any users with operating system root privileges.

ALTER DOMAIN allows you to:

Drop an existing default value.

Set a new default value.

Drop an existing CHECK constraint.

Add a new CHECK constraint.

The syntax for ALTER DOMAIN is:

ALTER DOMAIN name {
[SET DEFAULT {literal | NULL | USER}]
| [DROP DEFAULT]
| [ADD [CONSTRAINT] CHECK (<dom_search_condition>)]
| [DROP CONSTRAINT]
};

The complete syntax of ALTER DOMAIN is in the online SQL Reference.

The following statement sets a new default value for the CUSTNO domain:

ALTER DOMAIN CUSTNO SET DEFAULT 9999;


How to Drop Domains

DROP DOMAIN removes an existing domain definition from a database.

If a domain is currently used in any column definition in the database, the DROP operation fails. To prevent failure, delete the columns based on the domain with ALTER TABLE before executing DROP DOMAIN.

A domain may be dropped by its creator, the SYSDBA, and any users with operating system root privileges.

The syntax of DROP DOMAIN is:

DROP DOMAIN name;

The following statement deletes a domain:

DROP DOMAIN COUNTRYNAME;


Working With Tables

How to Create Tables

How to Alter Tables

How to Drop Tables


How to Create Tables

Create tables in the database with the CREATE TABLE statement:

CREATE TABLE table [EXTERNAL [FILE] "<filespec>"]
(<col_def> [, <col_def> | <tconstraint> ...]);

The first required argument you supply to CREATE TABLE is the table name which must be unique among all table and procedure names in the database and not on the InterBase reserved words list. You must also define at least one column.

The complete syntax of CREATE TABLE is in the online SQL Reference.

InterBase automatically imposes the default SQL security scheme on the table. The person who creates the table (the owner), is assigned all privileges for it, including the right to grant privileges to other users, triggers, and stored procedures.

Using the External File Option

How to Define Columns


Using the EXTERNAL FILE Option

The EXTERNAL FILE option creates a table for which the data resides in an external table or file, rather than in the InterBase database. External files are ASCII text that can also be read and manipulated by non-InterBase applications. See the syntax for CREATE TABLE. <filespec> is the fully qualified file specification for the external data file. You can modify the external file outside InterBase; InterBase accesses it only when needed.

Use the EXTERNAL FILE option to:

Import data from a flat external file in a known fixed-length format into a new or existing InterBase table. This allows you to populate an InterBase table with data from an external source. Many applications allow you to create an external file with fixed-length records.

Export data from an existing InterBase table to an external file. You can format the data from the InterBase table into a fixed-length file that another application can use.

Restrictions

The following restrictions apply to using the EXTERNAL FILE option:

You must create the external file before you try to access the external table inside of the database.

Each record in the external file must be of fixed length. You cannot put BLOB or array data into an external file.

When you create the table that will be used to import the external data, you must define a column to contain the end-of-line (EOL) or new-line character. The size of this column must be exactly large enough to contain a particular system's EOL symbol (usually one or two bytes). For most versions of Unix, it is 1 byte. For Windows, NT, and NetWare, it is 2 bytes.

While it is possible to read in numeric data directly from an external table, it is much easier to read it in as character data, and convert using the CAST( ) function.

Data to be treated as VARCHAR in InterBase must be stored in an external file in the following format:

<2-byte unsigned short><string of character bytes>

where the 2-byte unsigned short indicates the number of bytes in the actual string, and the string immediately follows. Because of its lack of easy portability, use of VARCHAR data in an external file is not recommended.

You can only INSERT into and SELECT from the rows of an external table. You cannot UPDATE or DELETE from an external table; if you try to do so, InterBase returns an error message.

Inserting into and selecting from an external table are not under standard transaction control because the external file is outside of the database. Therefore, changes are immediate and permanent--you cannot roll back your changes. If you want your table to be under transaction control, create another internal InterBase table, and insert the data from the external table into the internal one.

If you use DROP DATABASE to delete the database, you must also remove the external file--it will not be automatically deleted as a result of DROP DATABASE.


Importing Data From External Files

The following steps describe how to import an external file into an InterBase table:

1.	Create an InterBase table that allows you to view the external data. Declare all columns as CHAR. The text file containing the data must be on the server. In the following example, the external file exists on a Unix system, so the EOL character is 1 byte.

CREATE TABLE EXT_TBL EXTERNAL FILE "file.txt"

(

FNAME CHAR(10),
LNAME CHAR(20),
HDATE CHAR(8),
NEWLINE CHAR(1)

);

COMMIT;

2.	Create another InterBase table that will eventually be your working table. If you expect to export data from the internal table back to an external file at a later time, be sure to create a column to hold the newline. Otherwise, you do not need to leave room for the newline character. In the following example, a column for the newline is provided:

CREATE TABLE PEOPLE

(

FIRST_NAME CHAR(10),
LAST_NAME CHAR(20),
HIRE_DATE CHAR(8),
NEW_LINE CHAR(1)

);

COMMIT;

3.	Create and populate the external file. You can create the file with a text editor, or you can create an appropriate file with an application like Paradox for Windows or dBASE for Windows. If you create the file yourself with a text editor, make each record the same length, pad the unused characters with blanks, and insert the EOL character(s) at the end of each record.

Note:	The number of characters in the EOL character is platform-specific. You need to know how many characters are contained in your platform's EOL (typically one or two) in order to correctly format the columns of the tables and the corresponding records in the external file. In the following example, the record length is 36 characters. "b" represents a blank space, and "n" represents the EOL:

123456789012345678901234567890123456

fname.....lname.............hdate..n

------------------------------------

RobertbbbbBrickmanbbbbbbbbbb6/12/92n

SambbbbbbbJonesbbbbbbbbbbbb12/13/93n

4.	At this point, when you do a SELECT statement from table EXT_TBL, you will see the records from the external file:

SELECT FNAME, LNAME, HDATE FROM EXT_TBL;

FNAME     LNAME             HDATE

========  ================= ===========

Robert    Brickman          12-JUN-1992

Sam       Jones             13-DEC-1993

5.	Insert the data into the destination table.

INSERT INTO PEOPLE SELECT FNAME, LNAME, CAST(HDATE AS DATE), NEWLINE FROM EXT_TBL;

Now if you SELECT from PEOPLE, the data from your external table will be there.

SELECT FIRST_NAME, LAST_NAME, HIRE_DATE FROM PEOPLE;

FIRST_NAME LAST_NAME           HIRE_DATE

========== =================== ===========

Robert     Brickman            12-JUN-1992

Sam        Jones               13-DEC-1993

InterBase allows you to store the date as an integer by converting from a CHAR(8) to DATE using the CAST( ) function.


Exporting Data to an External File

If you add, update, or delete a record from an internal table, the changes will not be reflected in the external file. So in the previous example, if you delete the "Sam Jones" record from the PEOPLE table, and do a subsequent SELECT from EXT_TBL, you would still see the "Sam Jones" record.

This section explains how to export InterBase data to an external file. Using the example developed in the previous section, follow these steps:

1.	Open the external file in a text editor and remove everything from the file. If you then do a SELECT on EXT_TBL, it should be empty.

2.	Use an INSERT statement to copy the InterBase records from PEOPLE into the external file, file.txt.

INSERT INTO EXT_TBL SELECT FIRST_NAME, LAST_NAME, HIRE_DATE, NEW_LINE
FROM PEOPLE WHERE FIRST_NAME LIKE "Rob%";

3.	Now if you do a SELECT from the external table, EXT_TBL, only the records you inserted should be there. In this example, only a single record should be displayed:

SELECT FNAME, LNAME, HDATE FROM EXT_TBL;

FNAME     LNAME             HDATE

========  ================= ===========

Robert    Brickman          12-JUN-1992

Important:	Make sure that all records that you intend to export from the internal table to the external file have the correct EOL character(s) in the newline column.


How to Define Columns

When you create a table in the database, your main task is to define the various attributes and constraints for each of the columns in the table. The syntax for defining a column is:

<col_def> = col {datatype | COMPUTED [BY] (<expr>) | domain}
[DEFAULT {literal | NULL | USER}]
[NOT NULL] [<col_constraint>]
[COLLATE collation]

Required Attributes

A column name, which must be unique among the columns in the table.

One of the following:

An SQL data type (<datatype>).

A domain definition (<domain>) for a domain-based column.

An expression (<expr>) for a computed column.

Optional Attributes

A default value for the column.

Integrity constraints. Constraints can be applied to a set of columns (a table-level constraint), or to a single column (a column-level constraint). Integrity constraints include:

The PRIMARY KEY column constraint, if the column is a PRIMARY KEY, and the PRIMARY KEY constraint is not defined at the table level. Creating a PRIMARY KEY requires exclusive database access.

The UNIQUE constraint, if the column is not a PRIMARY KEY, but should still disallow duplicate and NULL values.

The FOREIGN KEY constraint, if the column references a PRIMARY KEY in another table. Creating a FOREIGN KEY requires exclusive database access.

A NOT NULL attribute does not allow NULL values. This attribute is required if the column is a PRIMARY KEY or UNIQUE key.

A CHECK constraint for the column. A CHECK constraint enforces a condition that must be true before an insert or an update to a column or group of columns is allowed.

A CHARACTER SET can be specified for a single column when you define the data type. If you do not specify a character set, the column assumes the database character set as a default.


Specifying the Data Type

Specify the data type for each column. The data type defines the set of valid data that the column can contain. The data type also determines the set of allowable operations that can be performed on the data, and defines the disk space requirements for each data item.

The syntax for specifying the data type is:

<datatype> = {
{SMALLINT | INTEGER | FLOAT | DOUBLE PRECISION} [<array_dim>]
| {DECIMAL | NUMERIC} [(precision [, scale])] [<array_dim>]
| DATE [<array_dim>]
| {CHAR | CHARACTER | CHARACTER VARYING | VARCHAR}
[(int)] [<array_dim>] [CHARACTER SET charname]
| {NCHAR | NATIONAL CHARACTER | NATIONAL CHAR}
[VARYING] [(int)] [<array_dim>]
| BLOB [SUB_TYPE {int | subtype_name}] [SEGMENT SIZE int]
[CHARACTER SET charname]
| BLOB [(seglen [, subtype])]
}

The general categories of data types that are supported include:

Numeric data types.

Character data types.

A DATE data type to represent date and time. InterBase does not directly support the SQL DATE, TIME, and TIMESTAMP data types.

A BLOB data type to represent unstructured binary data, such as graphics and digitized voice.

Note:	If your application programming language does not support a particular data type, InterBase either automatically converts the data to an equivalent data type (an implicit type conversion), or you can use the CAST( ) function in search conditions to explicitly translate one data type into another for comparison purposes.

InterBase supports the following data types:

Name: BLOB	Size: Variable

Range/Precision: None

Description: Binary large object. Stores large data, such as graphics, text, and digitized voice. Basic structural unit: segment. BLOB subtype describes BLOB contents.

Name: CHAR(n)	Size: n characters

Range/Precision: 1 to 32767 bytes. Character set character size determines the maximum number of characters that can fit in 32K.

Description: Fixed length CHAR or text string type. Alternate keyword: CHARACTER

Name: DATE	Size: 64 bits

Range/Precision: 1 Jan 100 to 11 Jan 5941

Description: Also includes time information.

Name: DECIMAL (precision, scale)	Size: variable

Range/Precision: precision = 1 to 15. Specifies at least precision digits of precision to store. scale = 1 to 15. Specifies number of decimal places for storage. Must be less than or equal to precision.

Description: Number with a decimal point scale digits from the right. For example, DECIMAL(10, 3) holds numbers accurately in the following format:

ppppppp.sss

Name: DOUBLE PRECISION	Size: 64 bits

Range/Precision: 1.7 X 10-308 to 1.7 X 10308

Description: Scientific: 15 digits of precision.

Note:	Actual size of DOUBLE is platform dependent. Most platforms support the 64 bit size.

Name: FLOAT	Size: 32 bits

Range/Precision: 3.4 X 10-38 to 3.4 X 1038

Description: Single precision: 7 digits of precision.

Name: INTEGER	Size: 32 bits

Range/Precision: 2,147,483,648 to 2,147,483,648

Description: Signed long (longword).

Name: NUMERIC (precision, scale)	Size: variable

Range/Precision: precision = 1 to 15. Specifies exactly precision digits of precision to store. scale = 1 to 15. Specifies number of decimal places for storage. Must be less than or equal to precision.

Description: Number with a decimal point scale digits from the right. For example, NUMERIC(10,3) holds numbers accurately in the following format:

ppppppp.sss

Name: SMALLINT	Size: 16 bits

Range/Precision: -32768 to 32767

Description: Signed short (word).

Name: VARCHAR (n)	Size: n characters

Range/Precision: 1 to 32767 bytes. Character set character size determines the maximum number of characters that can fit in 32K.

Description: Variable length CHAR or text string type. Alternate keywords: VARYING CHAR, VARYING CHARACTER


Numeric Data Types

The numeric data types that InterBase supports include:

Integer numbers of various sizes (INTEGER and SMALLINT)

Formatted, fixed-decimal numbers (DECIMAL, NUMERIC)

Floating-point numbers with variable precision (FLOAT, DOUBLE PRECISION)


Integer Data Types

Integers are whole numbers. InterBase supports two integer data types: SMALLINT and INTEGER. SMALLINT is a signed short integer with a range from -32,768 to 32,767. INTEGER is a signed long integer with a range from -2,147,483,648 to 2,147,483,647.

The next two statements create domains with the SMALLINT and INTEGER data types:

CREATE DOMAIN EMPNO
AS SMALLINT;

CREATE DOMAIN CUSTNO
AS INTEGER
CHECK (VALUE > 99999);

You can perform the following operations on the integer data types:

Comparisons using the standard relational operators (=, <, >, >=, <=). Other operators such as CONTAINING, STARTING WITH, and LIKE perform string comparisons on numeric values.

Arithmetic operations. The standard arithmetic operators determine the sum, difference, product, or dividend of two or more integers.

Conversions. When performing arithmetic operations that involve mixed data types, InterBase automatically converts between INTEGER, FLOAT, and CHAR data types. For operations that involve comparisons of numeric data with other data types, InterBase first converts the data to a numeric type, then performs the arithmetic operation or comparison.

Sorts. By default, a query retrieves rows in the exact order that it finds them in the table, which is likely to be unordered. You can sort rows using the ORDER BY clause of a SELECT statement in descending or ascending order.


Fixed-decimal Data Types

InterBase supports two SQL data types, NUMERIC, and DECIMAL, for handling numeric data with a fixed decimal point, such as monetary values. You can specify optional precision and scale factors for both data types. precision is the maximum number of total digits, both significant and fractional, that can appear in a column of these data types. scale is the number of digits to the right of the decimal point that comprise the fractional portion of the number. The allowable range for both precision and scale is from 1 to a maximum of 15, and scale must be less than or equal to precision.

The syntax for NUMERIC and DECIMAL is as follows:

NUMERIC[(precision [, scale])]

DECIMAL[(precision [, scale])]

You can specify NUMERIC and DECIMAL data types without precision or scale, with precision only, or with both precision and scale. When you specify a NUMERIC data type with both precision and scale, the exact number of digits that you specified in precision and scale are stored. For example:

NUMERIC(4,2)

declares that a column of this type always holds numbers with up to two significant digits, with exactly two digits to the right of the decimal point: pp.ss.

When you specify a DECIMAL data type with both precision and scale, the number of total digits stored is at least as many as you specified in precision, and the exact number of fractional digits that you specified in scale. For example:

DECIMAL(4,2)

declares that a column of this type must be capable of holding at least two, but possibly more significant digits, and exactly two digits to the right of the decimal point: pp.ss.

How InterBase Stores Fixed-decimal Data Types

When you create a domain or column with a NUMERIC or DECIMAL data type, InterBase determines which data type to use for internal storage based on the precision and scale that you specify. NUMERIC and DECIMAL data types store numbers in three ways:

Defined without precision or scale--always stored as INTEGER.

Defined with precision, but not scale--depending upon the precision specified, stored as SMALLINT, INTEGER, or DOUBLE PRECISION.

Defined with both precision and scale--depending upon the precision specified, stored as SMALLINT, INTEGER, or DOUBLE PRECISION.

The following table summarizes how InterBase stores NUMERIC and DECIMAL data types based on precision and scale:

Data Type Specified as . . .	Data Type Stored as . . .

NUMERIC	INTEGER

NUMERIC(4)	SMALLINT

NUMERIC(9)	INTEGER

NUMERIC(10)	DOUBLE PRECISION

NUMERIC(4,2)	SMALLINT

NUMERIC(9,3)	INTEGER

NUMERIC(10,4)	DOUBLE PRECISION

DECIMAL	INTEGER

DECIMAL(4)	INTEGER

DECIMAL(9)	INTEGER

DECIMAL(10)	DOUBLE PRECISION

DECIMAL(4,2)	INTEGER

DECIMAL(9,3)	INTEGER

DECIMAL(10,4)	DOUBLE PRECISION

Specifying NUMERIC and DECIMAL Without Scale

For a NUMERIC data type, if a precision of less than 5 is specified without scale, InterBase stores the data type as a SMALLINT. If the precision is less than 10, InterBase stores the type as an INTEGER. For precisions of 10 or greater, the data type is stored as DOUBLE PRECISION.

Therefore, when you declare NUMERIC and DECIMAL data types with a precision of 10 or greater, fractional numbers can be stored without specifying a scale.

For example, in ISQL, if you specify "NUMERIC(10)", and insert a 13-digit number "2555555.256789," the number is stored exactly as specified, with 13 digits of precision and six digits to the right of the decimal. Conversely, if you format the column as NUMERIC(9), and insert the same 13-digit number "2555555.256789," InterBase truncates the fraction and stores the number as an INTEGER, "2555555."

Similarly, for a DECIMAL data type, if a precision of less than 10 is specified without scale, InterBase stores the data type as INTEGER; otherwise, it stores the data type as DOUBLE PRECISION.

Important:	When you format the column as NUMERIC or DECIMAL with a precision of 10 or greater without scale, you lose the ability to control both scale and precision.

Using the same NUMERIC(10) example, when you insert the 13-digit number "2555555.256789," the number is stored exactly as specified, with 13 digits of precision and 6 digits to the right of the decimal. If you insert an 11-digit number "255555.25678," the number is also stored exactly as specified with 11 digits of precision, and 5 fractional digits. You might expect that the precision would always be 10 because you explicitly specified 10, but it also varies depending upon precision of the inserted data.

Tip:	If you want to store fixed-decimal numbers such as monetary values, do not declare NUMERIC or DECIMAL with a precision of 10 or greater without specifying scale. In addition, if you need to control the precision for decimal data, you must specify scale.

Specifying NUMERIC and DECIMAL With Scale and Precision

When a NUMERIC or DECIMAL data type declaration includes both precision and scale, values containing a fractional portion may be stored, and you can control the number of fractional digits. InterBase may store such values internally as SMALLINT, INTEGER, or DOUBLE PRECISION data, depending on the precision specified. How can a number with a fractional portion be stored as an integer value? For all SMALLINT and INTEGER data entered, InterBase stores:

A scale factor, a negative number indicating how many decimal places are contained in the number, based on the power of 10. A -1 scale factor indicates a fractional portion of tenths; a -2 scale factor indicates a fractional portion of hundredths. You do not need to include the sign; it is negative by default.

For example, when you specify NUMERIC(4,2), InterBase stores the number internally as a SMALLINT. If you insert the number "25.253," it is stored as a decimal "25.25," with 4 digits of precision, and a scale of 2.

The number is divided by 10 to the power of "scale" (number/10^scale) to produce a number without a fractional portion.

Specifying Data Types Using Embedded Applications

DSQL applications such as ISQL can correct for the scale factor for SMALLINT and INTEGER data types by examining the XSQLVAR sqlscale field and dividing to produce the correct value.

Important:	Embedded applications cannot use or recognize small precision NUMERIC or DECIMAL data types with fractional portions when they are stored as SMALLINT or INTEGER types. To avoid this problem, create all NUMERIC and DECIMAL data types that are to be accessed from embedded applications with a precision of 10 or more, which forces them to be stored as DOUBLE PRECISION. Again, remember to specify a scale if you want to control the precision and scale.

Both SQL and DSQL applications handle NUMERIC and DECIMAL types stored as DOUBLE PRECISION without problem.


Floating-point Data Types

InterBase provides two floating-point data types, FLOAT and DOUBLE PRECISION; the only difference is their size. FLOAT specifies a single-precision, 32-bit data type with a precision of approximately 7 decimal digits. DOUBLE PRECISION specifies a double-precision, 64-bit data type with a precision of approximately 15 decimal digits.

The precision of FLOAT and DOUBLE PRECISION is fixed by their size, but the scale is not, and you cannot control the formatting of the scale. With floating numeric data types, the placement of the decimal point can vary; the position of the decimal is allowed to "float." For example, in the same column, one value could be stored as "25.33333," and another could be stored as "25.333."

Use floating-point numbers when you expect the placement of the decimal point to vary, and for applications where the data values have a very wide range, such as in scientific calculations.

If the value stored is outside of the range of the precision of the floating-point number, then it is stored only approximately, with its least-significant digits treated as zeros. For example, if the type is FLOAT, you are limited to 7 digits of precision. If you insert a 10-digit number "25.33333312" into the column, it is stored as "25.33333."

The next statement creates a column, PERCENT_CHANGE, using a DOUBLE PRECISION type:

CREATE TABLE SALARY_HISTORY
( . . .
PERCENT_CHANGE DOUBLE PRECISION
DEFAULT 0
NOT NULL
CHECK (PERCENT_CHANGE BETWEEN -50 AND 50),
. . . );

You can perform the following operations on FLOAT and DOUBLE PRECISION data types:

Comparisons using the standard relational operators (=, <, >, >=, <=). Other operators such as CONTAINING, STARTING WITH, and LIKE perform string comparisons on the integer portion of floating data.

Arithmetic operations. The standard arithmetic operators determine the sum, difference, product, or dividend of two or more integers.

Conversions. When performing arithmetic operations that involve mixed data types, InterBase automatically converts between INTEGER, FLOAT, and CHAR data types. For operations that involve comparisons of numeric data with other data types, such as CHARACTER and INTEGER, InterBase first converts the data to a numeric type, then compares them numerically.

Sorts. By default, a query retrieves rows in the exact order that it finds them in the table, which is likely to be unordered. Sort rows using the ORDER BY clause of a SELECT statement in descending or ascending order.

The following CREATE TABLE statement provides an example of how the different numeric types can be used: an INTEGER for the total number of orders, a fixed DECIMAL for the dollar value of total sales, and a FLOAT for a discount rate applied to the sale.

CREATE TABLE SALES
( . . .
QTY_ORDERED INTEGER
DEFAULT 1
CHECK (QTY_ORDERED >= 1),
TOTAL_VALUE DECIMAL (9,2)
CHECK (TOTAL_VALUE >= 0),
DISCOUNT FLOAT
DEFAULT 0
CHECK (DISCOUNT >= 0 AND DISCOUNT <= 1));


Character Data Types

InterBase supports character string data types for:

Fixed-length character data

Variable-length character data


Fixed-length Character Data

InterBase supports two fixed-length string data types: CHAR(n), or alternately CHARACTER (n), and NCHAR(n), or alternately NATIONAL CHAR(n).

CHAR(n) or CHARACTER(n)

The CHAR(n) or CHARACTER(n) data type contains character strings. The number of characters n is fixed.

When the string to be stored or read contains less than n characters, InterBase fills in the blanks to make up the difference. If a string is larger than n, then the value is truncated. If you do not supply n, it will default to 1, so CHAR is the same as CHAR(1). The next statement illustrates this:

CREATE TABLE SALES
( . . .
PAID CHAR
DEFAULT 'n'
CHECK (PAID IN ('y', 'n'),
. . . );

Note:	InterBase compresses trailing blanks when it stores fixed-length strings, so data with trailing blanks uses the same amount of space as an equivalent variable-length string. When the data is read, InterBase reinserts the blanks. This saves disk space when the length of the data items varies widely.

NCHAR(n) or NATIONAL CHAR(n)

NCHAR(n) is exactly the same as CHARACTER(n), except that the ISO8859_1 character set is used by definition. Using NCHAR(n) is a shortcut for using the CHARACTER SET clause to specify the "ISO8859_1" character set for a column.

The next two CREATE TABLE examples are equivalent:

CREATE TABLE EMPLOYEE

( . . .
FIRST_NAME NCHAR(10),
LAST_NAME NCHAR(15),
. . . );

CREATE TABLE EMPLOYEE

( . . .
FIRST_NAME CHAR(10) CHARACTER SET "ISO8859_1",
LAST_NAME CHAR(15) CHARACTER SET "ISO8859_1",
. . . );


Variable-length Character Data

InterBase supports two variable-length string data types: VARCHAR(n), or alternately CHAR(n) VARYING, and NCHAR(n), or alternately NATIONAL CHAR(n) VARYING.

VARCHAR(n), CHAR VARYING(n), or CHARACTER VARYING(n)

VARCHAR(n) or CHAR VARYING(n), or CHARACTER VARYING(n) allows you to store the exact number of characters that is contained in your data, up to a maximum of n. You must supply n; there is no default to 1.

If the length of the data within a column varies widely, and you do not want to pad your character strings with blanks, use the VARCHAR(n) or CHARACTER VARYING(n) data type.

InterBase converts from variable-length character data to fixed-length character data by adding spaces to the value in the varying column until the column reaches its maximum length n. When the data is read, InterBase removes the blanks.

The main advantages of using the VARCHAR(n) data type are that it saves disk space, and since more rows fit on a disk page, the database server can search the table with fewer disk I/O operations. The disadvantage is that table updates can be slower than using a fixed-length column in some cases.

The next statement illustrates the VARCHAR(n) data type:

CREATE TABLE SALES
( . . .
ORDER_STATUS VARCHAR(7)
DEFAULT "new"
NOT NULL
CHECK (ORDER_STATUS IN ("new", "open", "shipped", "waiting")),
. . . );

NCHAR VARYING(n) or NATIONAL CHARACTER VARYING (n) or NATIONAL CHAR VARYING(n)

NCHAR VARYING(n) is exactly the same as VARCHAR(n), except that the ISO8859_1 character set is used. Using NCHAR VARYING(n) is a shortcut for using the CHARACTER SET clause of CREATE TABLE, CREATE DOMAIN, or ALTER TABLE to specify the ISO8859_1 character set.


The DATE Data Type

InterBase supports a DATE data type that stores dates as two 32-bit longwords. Valid dates are from 1-JAN-100 to 11-DEC-5941. The following statement creates DATE columns in the SALES table:

CREATE TABLE SALES
( . . .
ORDER_DATE DATE
DEFAULT "now"
NOT NULL,
SHIP_DATE DATE
CHECK (SHIP_DATE >= ORDER_DATE OR SHIP_DATE IS NULL),
. . . );

Note:	In the previous example, "now" returns the system date and time.

Most languages do not support the DATE data type. Instead they express dates as strings or structures. The DATE data type requires conversion to and from InterBase when entered or manipulated in a host-language program. There are two ways to use the DATE data type:

1.	Create a string in a format that InterBase understands (for example, "1-JAN-1994"). When you insert the date into a DATE column, InterBase automatically converts the text into the internal DATE format.

2.	Use the call interface routines provided by InterBase to do the conversion. isc_decode_date( ) converts from the InterBase internal DATE format to the C time structure. isc_encode_date( ) converts from the C time structure to the internal InterBase DATE format.

Note:	The string conversion described in item #1 does not work in the other direction. To read a date in an InterBase format and convert it to a C date variable, you must call isc_decode_date( ).


BLOB Data Types

InterBase provides the binary large object (BLOB) data type to store data that cannot easily be stored in one of the standard SQL data types. A BLOB is used to store very large data objects of indeterminate and variable size, such as bitmapped graphics images, vector drawings, sound files, video segments, chapter or book-length documents, or any other kind of multimedia information. Because a BLOB can hold different kinds of information, it requires special processing for reading and writing.

The BLOB data type provides the advantages of a database management system, including transaction control, maintenance by database utilities, and access using SELECT, INSERT, UPDATE, and DELETE statements. Use the BLOB data type to avoid storing pointers to non-database files.

BLOB Columns

BLOB Segment Length

BLOB Subtypes


BLOB Columns

BLOB columns can be defined in database tables like non-BLOB columns. For example, the following statement creates a table with a BLOB column:

CREATE TABLE PROJECT

(PROJ_ID PROJNO NOT NULL,

PROJ_NAME VARCHAR(20) NOT NULL UNIQUE,

PROJ_DESC BLOB,

TEAM_LEADER EMPNO,

PRODUCT PRODTYPE,

. . . );

Rather than storing BLOB data directly, a BLOB column stores a BLOB ID. A BLOB ID is a unique numeric value that references BLOB data. The BLOB data is stored elsewhere in the database, in a series of BLOB segments, units of BLOB data read and written in chunks. When a BLOB is created, data is written to it a segment at a time. Similarly, when a BLOB is read, it is read a segment at a time.

The following diagram shows the relationship between a BLOB column containing a BLOB ID and the BLOB data referenced by the BLOB ID:


BLOB Segment Length

When a BLOB column is defined in a table, the BLOB definition can specify the expected size of BLOB segments that are written to the column. Actually, for SELECT, INSERT, and UPDATE operations, BLOB segments can be of varying length. For example, during insertion, a BLOB might be read in as three segments, the first segment having length 30, the second having length 300, and the third having length 3.

The length of an individual segment is specified when it is written. For example, the following code fragment inserts a BLOB segment. The segment length is specified in the host variable, segment_length:

INSERT CURSOR BCINS VALUES (:write_segment_buffer:segment_length);

Defining Segment Length

gpre, the InterBase precompiler, is used to process embedded SQL statements inside applications. The segment length setting, defined for a BLOB column when it is created, is used to determine the size of the internal buffer where the BLOB segment data will be written. This setting specifies (to gpre) the maximum number of bytes that an application is expected to write to any segment in the column. The default segment length is 80. Normally, an application should not attempt to write segments larger than the segment length defined in the table; doing so overflows the internal segment buffer, corrupting memory in the process.

The segment length setting does not affect InterBase system performance. Choose the segment length most convenient for the specific application. The largest possible segment length is 32 kilobytes (32,767 bytes).

The following statement creates two BLOB columns, BLOB1, with a default segment size of 80, and BLOB2, with a specified segment length of 512:

CREATE TABLE TABLE2

(BLOB1 BLOB,

BLOB2 BLOB SEGMENT SIZE 512);


BLOB Subtypes

When a BLOB column is defined, its subtype can be specified. A BLOB subtype is a positive or negative integer that describes the nature of the BLOB data contained in the column. InterBase provides two predefined subtypes, 0, signifying that a BLOB contains binary data, the default, and 1, signifying that a BLOB contains ASCII text. User-defined subtypes must always be represented as negative integers. Positive integers are reserved for use by InterBase.

For example, the following statement defines three BLOB columns: BLOB1 with subtype 0 (the default), BLOB2 with InterBase subtype 1 (TEXT), and BLOB3 with user-defined subtype -1:

CREATE TABLE TABLE2

(BLOB1 BLOB,
BLOB2 BLOB SUB_TYPE 1,
BLOB3 BLOB SUB_TYPE -1);

The application is responsible for ensuring that data stored in a BLOB column agrees with its subtype. For example, if subtype -10 denotes a certain data type in a particular application, then the application must ensure that only data of that data type is written to a BLOB column of subtype -10. InterBase does not check the type or format of BLOB data.

To specify both a default segment length and a subtype when creating a BLOB column, use the SEGMENT SIZE option after the SUB_TYPE option, as in the following example:

CREATE TABLE TABLE2

(BLOB1 BLOB SUB_TYPE 1 SEGMENT SIZE 100 CHARACTER SET DOS437;);


Converting Data Types

Normally, you must use compatible data types to perform arithmetic operations, or to compare data in search conditions. If you need to perform operations on mixed data types, or if your programming language uses a data type that is not supported by InterBase, then data type conversions must be performed before the database operation can proceed. InterBase either automatically converts the data to an equivalent data type (an implicit type conversion), or you can use the CAST( ) function in search conditions to explicitly translate one data type into another for comparison purposes.

Implicit Type Conversions

InterBase automatically converts columns of an unsupported data type to an equivalent one, if required. This is an implicit data type conversion. For example, in the following operation,

3 + '1' = 4

InterBase automatically converts the character "1" to an INTEGER for the addition operation.

The next example returns an error because InterBase cannot convert the "a" to an INTEGER:

3 + 'a' = 4

Explicit Type Conversions

When InterBase cannot do an implicit type conversion, you must perform an explicit type conversion using the CAST( ) function. Use CAST( ) to convert one data type to another inside a SELECT statement. Typically, CAST( ) is used in the WHERE clause to compare different data types. The syntax is:

CAST (<value> | NULL AS datatype)

Use CAST( ) to translate a:

DATE data type into a CHARACTER or NUMERIC data type.

CHARACTER data type into a NUMERIC or DATE data type.

NUMERIC data type into a CHARACTER or DATE data type.

For example, in the following WHERE clause, CAST( ) is used to translate a CHAR data type, INTERVIEW_DATE, to a DATE data type in order to compare against a DATE data type, HIRE_DATE:

. . . WHERE HIRE_DATE = (CAST(INTERVIEW_DATE AS DATE);

In the next example, CAST( ) is used to translate a DATE data type into a CHAR data type:

. . . WHERE CAST(HIRE_DATE AS CHAR) = INTERVIEW_DATE;

CAST( ) can be used to compare columns with different data types in the same table, or across tables.


Defining Domain-based Columns
Domain-based Columns

When you create a table, you can set column attributes by using an existing domain definition that has been previously stored in the database. A domain is a global column definition. Domains must be created with the CREATE DOMAIN statement before you can reference them to define columns locally.

Domain-based columns inherit all the characteristics of a domain, but the column definition can include a new default value, additional CHECK constraints, or a collation clause that overrides the domain definition. It can also include additional column constraints. You can specify a NOT NULL setting if the domain does not already define one.

Note:	You cannot override the domain's NOT NULL setting with a local column definition.

For example, the following statement creates a table, COUNTRY, referencing the domain, COUNTRYNAME, which was previously defined with a data type of VARCHAR(15):

CREATE TABLE COUNTRY

(COUNTRY COUNTRYNAME NOT NULL PRIMARY KEY,
CURRENCY VARCHAR(10) NOT NULL);


Computed Columns

A computed column is one whose value is calculated each time the column is accessed at run time. The syntax is:

<col_name> COMPUTED [BY] (<expr>);

If you do not specify the data type, InterBase calculates an appropriate one. <expr> is any arithmetic expression that is valid for the data types in the columns; it must return a single value, and cannot be an array or return an array. Columns referenced in the expression must exist before the COMPUTED [BY] clause can be defined.

For example, the following statement creates a computed column, FULL_NAME, by concatenating the LAST_NAME and FIRST_NAME columns.

CREATE TABLE EMPLOYEE

(FIRST_NAME VARCHAR(10) NOT NULL,
LAST_NAME VARCHAR(15) NOT NULL,
FULL_NAME COMPUTED BY (LAST_NAME || ", " || FIRST_NAME));

The next example creates a table with a calculated column (NEW_SALARY) using the previously created EMPNO and SALARY domains.

CREATE TABLE SALARY_HISTORY

(EMP_NO EMPNO NOT NULL,

CHANGE_DATE DATE DEFAULT "NOW" NOT NULL,

UPDATER_ID VARCHAR(20) NOT NULL,

OLD_SALARY SALARY NOT NULL,

PERCENT_CHANGE DOUBLE PRECISION

DEFAULT 0

NOT NULL

CHECK (PERCENT_CHANGE BETWEEN -50 AND 50),

NEW_SALARY COMPUTED BY

(OLD_SALARY + OLD_SALARY * PERCENT_CHANGE / 100),

PRIMARY KEY (EMP_NO, CHANGE_DATE, UPDATER_ID),

FOREIGN KEY (EMP_NO) REFERENCES EMPLOYEE (EMP_NO));

Note:	Constraints on computed columns are not enforced, but InterBase does not return an error if you do define such a constraint.


Column Default Values

You can set an optional default value that is automatically entered into a column if you do not specify an explicit value. Defaults set at the column level with CREATE TABLE or ALTER TABLE override defaults set at the domain level. Defaults can save data entry time and prevent data entry errors. For example, a possible default for a DATE column could be today's date, or in a (Y/N) flag column for saving changes, "Y" could be the default.

Default values can be:

literal--The default value is a user-specified string, numeric value, or date value.

NULL--If the user does not enter a value, a NULL value is entered into the column.

USER--The default is the name of the current user. If your operating system supports the use of 8 or 16-bit characters in user names, then the column into which USER will be stored must be defined using a compatible character set.

In the following example, the first statement creates a domain with USER named as the default. The next statement creates a table that includes a column, ENTERED_BY, based on the USERNAME domain.

CREATE DOMAIN USERNAME AS VARCHAR(20)
DEFAULT USER;

CREATE TABLE ORDERS (ORDER_DATE DATE, ENTERED_BY USERNAME, ORDER_AMT DECIMAL(8,2));

INSERT INTO ORDERS (ORDER_DATE, ORDER_AMT)
VALUES ("1-MAY-93", 512.36);

The INSERT statement does not include a value for the ENTERED_BY column, so InterBase automatically inserts the user name of the current user, JSMITH:

SELECT * FROM ORDERS;

1-MAY-93 JSMITH 512.36


Integrity Constraints
Defining Integrity Constraints

InterBase allows you to optionally apply certain constraints to a column, called integrity constraints, which are the rules that govern column-to-table and table-to-table relationships, and validate data entries. They span all transactions that access the database and are automatically maintained by the system. Integrity constraints can be applied to an entire table or to an individual column.

PRIMARY KEY and UNIQUE Constraints

FOREIGN KEY Constraints

Circular References

How to Declare Constraints


PRIMARY KEY and UNIQUE Constraints

The PRIMARY KEY and UNIQUE integrity constraints ensure that the values entered into a column or set of columns are unique in each row. If you try to insert a duplicate value in a PRIMARY KEY or UNIQUE column, the database will prevent the operation and return an error. When you define a UNIQUE or PRIMARY KEY column, determine whether the data stored in the column is inherently unique. For example, no two social security numbers or driver's license numbers are ever the same. If no single column has this property, then define the primary key as a composite of two or more columns which, when taken together, are unique.

EMP_NO	LAST_NAME	FIRST_NAME	JOB_TITLE	PHONE_EXT

10335	Smith	John	Engineer	4968
21347	Carter	Catherine	Product Manager	4967
13314	Jones	Sarah	Senior Writer	4800
In the EMPLOYEE table, EMP_NO is the primary key that uniquely identifies each employee. EMP_NO is the primary key because no two values in the column are alike. If the EMP_NO column did not exist, then no other column is a candidate for primary key due to the high probability for duplication of values. LAST_NAME, FIRST_NAME, and JOB_TITLE fail because more than one employee can have the same first name, last name, and job title. In a large database, a combination of LAST_NAME and FIRST_NAME could still result in duplicate values. A primary key that combines LAST_NAME and PHONE_EXT might work, but there could be two people with identical last names at the same extension. In this table, the EMP_NO column is actually the only acceptable candidate for the primary key because it guarantees a unique number for each employee in the table.

A table can have only one primary key. If you define a PRIMARY KEY constraint at the table level, you cannot do it again at the column level. The reverse is also true; if you define a PRIMARY KEY constraint at the column level, you cannot define a primary key at the table level. You must define the NOT NULL attribute for a PRIMARY KEY column in order to preserve the uniqueness of the data values in that column.

Like primary keys, a unique key ensures that no two rows have the same value for a specified column or ordered set of columns. You must define the NOT NULL attribute for a UNIQUE column. A unique key is different from a primary key in that the UNIQUE constraint specifies alternate keys that you can use to uniquely identify a row. You can have more than one unique key defined for a table, but the same set of columns cannot make up more than one PRIMARY KEY or UNIQUE constraint for a table. Like a primary key, a unique key can be referenced by a foreign key in another table.


FOREIGN KEY Constraints

A foreign key is a column or set of columns in one table that correspond in exact order to a column or set of columns defined as a primary key in another table. For example, in the PROJECT table, TEAM_LEADER is a foreign key referencing the primary key, EMP_NO in the EMPLOYEE table.

PROJ_ID	TEAM_LEADER	PROJ_NAME	PROJ_DESC	PRODUCT

DGPII	44	Automap	blob data	hardware
VBASE	47	Video database	blob data	software
HWRII	24	Translator upgrade	blob data	software
EMP_NO	LAST_NAME	FIRST_NAME	DEPT_NO	JOB_CODE	PHONE_EXT	SALARY

24	Smith	John	100	Eng	4968	64000
48	Carter	Catherine	900	Sales	4967	72500
36	Smith	Jane	600	Admin	4800	37500
The primary reason for defining foreign keys is to ensure that the integrity of the data is maintained when more than one table references the same data--rows in one table must always have corresponding rows in the referencing table.

InterBase enforces referential integrity in the following ways:

Before a foreign key can be added, the unique or primary key columns that the foreign key references must already be defined.

If information is changed in one place, it must be changed in every other place that it appears. For example, to change a value in the EMP_NO column of the EMPLOYEE table (the primary key), that value must also be updated in the TEAM_LEADER column of the PROJECT table (the foreign key).

If the user were allowed to delete a row containing a primary key in one table, the meaning of any rows in another table that contain that value as a foreign key is lost. To preserve referential integrity, InterBase prevents anyone from deleting values from a primary key column that have matching foreign keys in another referencing table. The user must first delete all foreign key rows before deleting the primary key to which they refer.

The database also prevents users from adding a value in a column defined as a foreign key that does not reference an existing primary key value. For example, to change a value in the TEAM_LEADER column of the PROJECT table, that value must first be updated in the EMP_NO column of the EMPLOYEE table.


Circular References

When two tables reference each other's foreign keys and primary keys, a circular reference exists between the two tables. In the following illustration, the foreign key in the EMPLOYEE table, DEPT_NO, references the primary key, DEPT_NO, in the DEPARTMENT table. Therefore, the primary key, DEPT_NO must be defined in the DEPARTMENT table before it can be referenced by a foreign key in the EMPLOYEE table. In the same manner, EMP_NO, which is the EMPLOYEE table's primary key, must be created before the DEPARTMENT table can define EMP_NO as its foreign key.

The problem with circular referencing occurs when you try to insert a new row into either table. Inserting a new row into the EMPLOYEE table causes a new value to be inserted into the DEPT_NO (foreign key) column, but you cannot insert a value into the foreign key column unless that value already exists in the DEPT_NO (primary key) column of the DEPARTMENT table. It is also true that you cannot add a new row to the DEPARTMENT table unless the values placed in the EMP_NO (foreign key) column already exist in the EMP_NO (primary key) column of the EMPLOYEE table. Therefore, you are in a deadlock situation because you cannot add a new row to either table!

InterBase gets around the problem of circular referencing by allowing you to insert a NULL value into a foreign key column before the corresponding primary key value exists. The following example illustrates the sequence for inserting a new row into each table:

Insert a new row into the EMPLOYEE table by placing "1" in the EMP_NO primary key column, and a NULL in the DEPT_NO foreign key column.

Insert a new row into the DEPARTMENT table, placing "2" in the DEPT_NO primary key column, and "1" in the foreign key column.

Use ALTER TABLE to modify the EMPLOYEE table. Change the DEPT_NO column from NULL to "2."


How to Declare Constraints

When declaring a table-level or a column-level constraint, you can optionally name the constraint using the CONSTRAINT clause. If you omit the CONSTRAINT clause, InterBase generates a unique system constraint name which is stored in the system table, RDB$RELATION_CONSTRAINTS.

Tip:	To ensure that the constraint names are visible in RDB$RELATION_CONSTRAINTS, commit your transaction before trying to view the constraint in the RDB$RELATION_CONSTRAINTS system table.

The syntax for a column-level constraint is:

<col_constraint> = [CONSTRAINT constraint] <constraint_def>
[<col_constraint> ...]

<constraint_def> = {UNIQUE | PRIMARY KEY
| CHECK (<search_condition>)
| REFERENCES other_table [(other_col [, other_col ...])]}

The syntax for a table-level constraint is:

<tconstraint> = [CONSTRAINT constraint] <tconstraint_def>
[<tconstraint> ...]

<tconstraint_def> = {{PRIMARY KEY | UNIQUE} (col [, col ...])
| FOREIGN KEY (col [, col ...]) REFERENCES other_table
| CHECK (<search_condition>)}

Tip:	Although naming a constraint is optional, assigning a descriptive name with the CONSTRAINT clause can make the constraint easier to find for changing or dropping, and easier to find when its name appears in a constraint violation error message.

The following statement illustrates how to create a simple, column-level PRIMARY KEY constraint:

CREATE TABLE COUNTRY

(COUNTRY COUNTRYNAME NOT NULL PRIMARY KEY,

CURRENCY VARCHAR(10) NOT NULL);

The next example illustrates how to create a UNIQUE constraint at both the column level and the table level:

CREATE TABLE STOCK
(MODEL SMALLINT NOT NULL UNIQUE,
MODELNAME CHAR(10) NOT NULL,
ITEMID INTEGER NOT NULL, CONSTRAINT MOD_UNIQUE UNIQUE (MODELNAME, ITEMID));


Specifying NOT NULL

You can optionally specify NOT NULL to force the user to enter a value. If you do not specify NOT NULL, then NULL values are allowed in the column. You cannot override a NOT NULL setting that has been set at a domain level with a local column definition.

Note:	If you have already specified NULL as a default value, be sure not to create contradictory constraints by also specifying the NOT NULL attribute, as in the following example:

CREATE TABLE MY_TABLE (COUNT INTEGER DEFAULT NULL, NOT NULL);


CHECK Constraints

You can specify a condition or requirement on a data value at the time the data is entered by applying a CHECK constraint to a column. Use CHECK constraints to enforce a condition that must be true before an insert or an update to a column or group of columns is allowed. The search condition verifies whether the value entered falls within a certain permissible range, or matches it to one value in a list of values. The search condition can also compare the value entered with data values in other columns.

Note:	A CHECK constraint will only guarantee data integrity when the values being verified are in the same row that is being inserted and deleted. If you try to compare values in different rows of the same table or in different tables, another user could later modify those values, thus invalidating the original CHECK constraint that was applied at insertion time.

In the following example, the CHECK constraint is guaranteed to be satisfied:

CHECK (VALUE (COL_1 > COL_2));

INSERT INTO TABLE_1 (COL_1, COL_2) VALUES (5,6);

The syntax for creating a CHECK constraint is:

CHECK (<search condition>);

<search_condition> = {<val> <operator>
{<val> | (<select_one>)}
| <val> [NOT] BETWEEN <val> AND <val>
| <val> [NOT] LIKE <val> [ESCAPE <val>]
| <val> [NOT] IN (<val> [, <val> ...] | <select_list>)
| <val> IS [NOT] NULL
| <val> {[NOT] {= | < | >} | >= | <=}
{ALL | SOME | ANY} (<select_list>)
| EXISTS (<select_expr>)
| SINGULAR (<select_expr>)
| <val> [NOT] CONTAINING <val>
| <val> [NOT] STARTING [WITH] <val>
| (<search_condition>)
| NOT <search_condition>
| <search_condition> OR <search_condition>
| <search_condition> AND <search_condition>}

When creating CHECK constraints, the following restrictions apply:

A CHECK constraint cannot reference a domain.

A column can have only one CHECK constraint.

On a domain-based column, you cannot override a CHECK constraint imposed by the domain with a local CHECK constraint. A column based on a domain can add additional CHECK constraints to the local column definition.

In the next example, a CHECK constraint is placed on the SALARY domain. VALUE is a placeholder for the name of a column that will eventually be based on the domain.

CREATE DOMAIN BUDGET
AS NUMERIC(12,2)
DEFAULT 0
CHECK (VALUE > 0);

The next statement illustrates PRIMARY KEY, FOREIGN KEY, and CHECK constraints. The PRIMARY KEY constraint is based on three columns, so it is a table-level constraint. The FOREIGN KEY column (JOB_COUNTRY) references the PRIMARY KEY column (COUNTRY) in the table, COUNTRY. This example also illustrates using domains (JOBCODE, JOBGRADE, COUNTRYNAME, SALARY) and a CHECK constraint to define columns:

CREATE TABLE JOB

(JOB_CODE JOBCODE NOT NULL,

JOB_GRADE JOBGRADE NOT NULL,

JOB_COUNTRY COUNTRYNAME NOT NULL,

JOB_TITLE VARCHAR(25) NOT NULL,

MIN_SALARY SALARY NOT NULL,

MAX_SALARY SALARY NOT NULL,

JOB_REQUIREMENT BLOB(400,1),

LANGUAGE_REQ VARCHAR(15) [5],

PRIMARY KEY (JOB_CODE, JOB_GRADE, JOB_COUNTRY),

FOREIGN KEY (JOB_COUNTRY) REFERENCES COUNTRY (COUNTRY),

CHECK (MIN_SALARY < MAX_SALARY));


Specifying a Character Set

The data type specification for a CHAR, VARCHAR, or BLOB text column definition can include a CHARACTER SET clause to specify a particular character set for a column. If you do not specify a character set, the column assumes the default database character set. If the database default character set is subsequently changed, all columns defined after the change have the new character set, but existing columns are not affected.

You can also change the default character set with SET NAMES in command-line ISQL or with the Session | Advanced Settings command in Windows ISQL.

The character set determines:

What characters can be used in CHAR, VARCHAR, and BLOB text columns.

The collation order to be used in sorting the column.

Note:	Collation order does not apply to BLOB data.

For example, the following statement creates a column that uses the ISO8859_1 character set, which is typically used in Europe to support European languages:

CREATE TABLE EMPLOYEE

(FIRST_NAME VARCHAR(10) CHARACTER SET ISO8859_1,
. . . );

Characters vs. Bytes

The number of bytes that the system uses to store a single character can vary depending upon the character set. InterBase limits a character column to 32,767 bytes. Some character sets require two or three bytes per character, so the maximum number of characters allowed in n varies depending upon the character set used.

In the case of a single-byte character column, one character is stored in one byte, so the internal memory used to store the string is also 32,767 bytes. Therefore, you can define 32,767 characters per single-byte column without encountering an error.

In the case of multi-byte characters, one character does not equal one byte. In the following example, the user specifies a CHAR data type using the UNICODE_FSS character set:

CHAR (10922) CHARACTER SET UNICODE_FSS; /* succeeds */

CHAR (10923) CHARACTER SET UNICODE_FSS; /* fails */

This character set has a maximum size of 3 bytes for a single character. Because each character requires 3 bytes of internal storage, the maximum number of characters allowed without encountering an error is 10,922 (32,767 divided by 3 is approximately 10,922).

Note:	To determine the maximum number of characters allowed in the data definition statement of any multi-byte column, look up the number of bytes per character. Then divide 32,767 (the internal byte storage limit for any character data type) by the number of bytes for each character. Two-byte character sets have a character limit of 16,383 per field, and a three-byte character set has a limit of 10,922 characters per field.

Using CHARACTER SET NONE

If a default character set was not specified when the database was created, the character set defaults to NONE. Using CHARACTER SET NONE means that there is no character set assumption for columns; data is stored and retrieved just as you originally entered it. You can load any character set into a column defined with NONE, but you cannot load that same data into another column that has been defined with a different character set. No transliteration will be performed between the source and destination character sets, so in most cases, errors will occur during the attempted assignment.

For example:

CREATE TABLE MYDATA (PART_NUMBER CHARACTER(30) CHARACTER SET NONE);

SET NAMES LATIN1;

INSERT INTO MYDATA (PART_NUMBER) VALUES("à");

SET NAMES DOS437;

SELECT * FROM MYDATA;

The data ("à") is returned just as it was entered, without the à being transliterated from the input character (LATIN1) to the output character (DOS437). If the column had been set to anything other than NONE, the transliteration would have occurred.

The COLLATE Clause

Each character set has its own subset of possible collation orders. The collation order determines the order in which values are sorted. The character set that you choose when you define the data type limits your choice of collation orders. The COLLATE clause of CREATE TABLE allows you to specify a particular collation order for columns defined as CHAR and VARCHAR text data types. You must choose a collation order that is supported for the column's given character set. The character set is either the default character set for the entire database, or you can specify a different set in the CHARACTER SET clause of the data type definition. The collation order set at the column level overrides a collation order set at the domain level.

In the following statement, BOOKNO keeps the default collating order for the database's default character set. The second (TITLE) and third (EUROPUB) columns specify different character sets and collating orders.

CREATE TABLE BOOKADVANCE (BOOKNO CHAR(6),
TITLE CHAR(50) CHARACTER SET DOS437 COLLATE PDOX_INTL,
EUROPUB CHAR(50) CHARACTER SET ISO8859_1 COLLATE FR_FR);

For a complete discussion on character sets and collation orders, see Character Sets and Collation Orders.


How to Alter Tables

Use ALTER TABLE to modify the structure of an existing table. ALTER TABLE enables you to:

Add a new column to a table.

Drop a column from a table.

Add integrity constraints to a table or column.

Drop integrity constraints from a table or column.

You can perform any number of the above operations with a single ALTER TABLE statement. A table can be altered by its creator, the SYSDBA user, and any users with operating system root privileges.

Before attempting to drop or modify a column, you should be aware of the different ways that ALTER TABLE can fail:

The person attempting to alter data does not have the required privileges.

Current data in a table violates a PRIMARY KEY or UNIQUE constraint definition added to the table; there is duplicate data in columns that you are trying to define as PRIMARY KEY or UNIQUE.

The column to be dropped is part of a UNIQUE, PRIMARY, or FOREIGN KEY constraint.

The column is used in a CHECK constraint. When altering a column based on a domain, you can supply an additional CHECK constraint for the column. Changes to tables that contain CHECK constraints with subqueries may cause constraint violations.

The column is used in another view, trigger, or in the value expression of a computed column.

Important:	You must drop the constraint or computed column before dropping the table column. You cannot drop PRIMARY KEY and UNIQUE constraints if they are referenced by FOREIGN KEY constraints. In this case, drop the FOREIGN KEY constraint before dropping the PRIMARY KEY or UNIQUE key it references. Finally, you can drop the column.

Before modifying or dropping columns in a table, you need to:

1.	Save the existing data.

2.	Drop any constraints on the column.

The complete syntax of ALTER TABLE is in the online SQL Reference.


Saving Existing Data

Before modifying an existing column definition using ALTER TABLE, you must preserve existing data, or it will be lost.

Preserving data in a column and modifying the definition for a column, is a six-step process:

1.	Add a temporary column to the table whose definition mirrors the current column to be changed.

2.	Copy the data from the column to be changed to the temporary column.

3.	Drop the column to be changed.

4.	Add a new column definition, giving it the same name as the dropped column.

5.	Copy the data from the temporary column to the new column.

6.	Drop the temporary column.

For example, suppose the EMPLOYEE table contains a column, OFFICE_NO, defined to hold a data type of CHAR(3), and suppose that the size of the column needs to be increased by one. The following numbered sequence describes each step and provides sample code:

1.	First, create a temporary column to hold the data in OFFICE_NO during the modification process:

ALTER TABLE EMPLOYEE ADD TEMP_NO CHAR(3);

2.	Move existing data from OFFICE_NO to TEMP_NO to preserve it:

UPDATE EMPLOYEE
SET TEMP_NO = OFFICE_NO;

3.	After the data is moved, drop the OFFICE_NO column:

ALTER TABLE DROP OFFICE_NO;

4.	Add a new column definition for OFFICE_NO, specifying the data type and new size:

ALTER TABLE ADD OFFICE_NO CHAR(4);

5.	Move the data from TEMP_NO to OFFICE_NO:

UPDATE EMPLOYEE
SET OFFICE_NO = TEMP_NO;

6.	Finally, drop the TEMP_NO column:

ALTER TABLE DROP TEMP_NO;


Adding New Columns

The syntax for adding a column with ALTER TABLE is:

ALTER TABLE table ADD <col_def>

<col_def> = col {<datatype> | [COMPUTED [BY] (<expr>) | domain}
[DEFAULT {literal | NULL | USER}]
[NOT NULL] [<col_constraint>]
[COLLATE collation]

<col_constraint> = [CONSTRAINT constraint] <constraint_def>
[<col_constraint>]

<constraint_def> = {PRIMARY KEY | UNIQUE
| CHECK (<search_condition>)
| REFERENCES other_table [(other_col [, other_col ...])]}

For example, the following statement adds a column, EMP_NO, to the EMPLOYEE table using the EMPNO domain:

ALTER TABLE EMPLOYEE ADD EMP_NO EMPNO NOT NULL;

You can add multiple columns to a table at the same time. Separate column definitions with commas. For example, the following statement adds two columns, EMP_NO, and FULL_NAME, to the EMPLOYEE table. FULL_NAME is a computed column, a column that derives it values from calculations based on two other columns already defined for the EMPLOYEE table:

ALTER TABLE EMPLOYEE
ADD EMP_NO EMPNO NOT NULL,
ADD FULL_NAME COMPUTED BY (LAST_NAME || ', ' || FIRST_NAME);

You can also define integrity constraints for columns that you add to the table. For example, the next statement adds two columns, CAPITAL and LARGEST_CITY, to the COUNTRY table, and defines a UNIQUE constraint on CAPITAL:

ALTER TABLE COUNTRY
ADD CAPITAL VARCHAR(25) UNIQUE,
ADD LARGEST_CITY VARCHAR(25) NOT NULL;


Dropping Columns

Dropping an Existing Column From a Table

You can use ALTER TABLE to delete a column definition and its data from a table. A column can be dropped only by the owner of the table. If another user is accessing a table when you attempt to drop a column, the other user's transaction will continue to have access to the table until that transaction completes. InterBase postpones the drop until the table is no longer in use.

The syntax for dropping a column with ALTER TABLE is:

ALTER TABLE name DROP colname [, colname ...];

For example, the following statement drops the EMP_NO column from the EMPLOYEE table:

ALTER TABLE EMPLOYEE DROP EMP_NO;

Multiple columns may be dropped with a single ALTER TABLE statement.

ALTER TABLE EMPLOYEE
DROP EMP_NO,
DROP FULL_NAME;

Important:	You cannot delete a column that is part of a UNIQUE, PRIMARY KEY, or FOREIGN KEY constraint. In the previous example, EMP_NO is the PRIMARY KEY for the EMPLOYEE table, so you cannot drop this column unless you first drop the PRIMARY KEY constraint.

Caution:	When a column is altered or dropped, any data stored in it is lost.


Adding New Constraints

You can use ALTER TABLE to add a new table-level constraint. The syntax is:

ALTER TABLE name ADD [CONSTRAINT constraint] <tconstraint_opt>;

Where <tconstraint_opt> is a PRIMARY KEY, FOREIGN KEY, UNIQUE, or CHECK constraint. For example:

ALTER TABLE EMPLOYEE
ADD CONSTRAINT DEPT_NO UNIQUE;


Dropping Constraints From a Column

You must drop constraints from a column in the correct sequence. See the following CREATE TABLE example. Because there is a foreign key in the PROJECT table that references the primary key (EMP_NO) of the EMPLOYEE table, you must first drop the foreign key reference before you can drop the PRIMARY KEY constraint in the EMPLOYEE table.

CREATE TABLE PROJECT

(PROJ_ID PROJNO NOT NULL,
PROJ_NAME VARCHAR(20) NOT NULL UNIQUE,
PROJ_DESC BLOB(800,1),
TEAM_LEADER EMPNO,
PRODUCT PRODTYPE,

PRIMARY KEY (PROJ_ID),
CONSTRAINT TEAM_CONSTRT FOREIGN KEY (TEAM_LEADER) REFERENCES
EMPLOYEE (EMP_NO));

The proper sequence is:

ALTER TABLE PROJECT
DROP CONSTRAINT TEAM_CONSTRT;

ALTER TABLE EMPLOYEE
DROP CONSTRAINT EMP_NO_CONSTRT;

ALTER TABLE EMPLOYEE
DROP EMP_NO;

Note:	Constraint names are in the system table, RDB$RELATION_CONSTRAINTS.

In addition, you cannot delete a column if it is referenced by another column's CHECK constraint. To drop the column, first drop the CHECK constraint, then drop the column.


How to Drop Tables

Use DROP TABLE to remove a table's data, metadata, and indexes from a database. It also drops any triggers that are based on the table. A table can be dropped by its creator, the SYSDBA user, or any user with operating system root privileges.

Note:	If you only want to drop columns from a table, use ALTER TABLE.

You cannot drop a table that is referenced in a computed column, a view, integrity constraint, or stored procedure. You cannot drop a table that is being used by an active transaction until the table is no longer in use.

DROP TABLE fails and returns an error if:

The person who attempts to drop the table is not the owner of the table.

The table is in use when the drop is attempted. The drop is postponed until the table is no longer in use.

The table has a UNIQUE or PRIMARY KEY defined for it, and the PRIMARY KEY is referenced by a FOREIGN KEY in another table. First drop the FOREIGN KEY constraints in the other table, then drop the table.

The table is used in a view, trigger, stored procedure, or computed column. Remove the other elements before dropping the table.

The table is referenced in another table's CHECK constraint.

Note:	DROP TABLE does not drop external tables; it only removes the table definition from the database. You must explicitly delete the external file.

DROP TABLE Syntax

DROP TABLE name;

The following statement drops the table, COUNTRY:

DROP TABLE COUNTRY;


Character Sets and Collation Orders

CHAR, VARCHAR, and text BLOB columns in InterBase can use many different character sets. A character set defines the symbols that can be entered as text in a column, and its also defines the maximum number of bytes of storage necessary to represent each symbol. In some character sets, such as ISO8859_1, each symbol requires only a single byte of storage. In others, such as UNICODE_FSS, each symbol requires from 1 to 3 bytes of storage.

Each character set also has an implicit collation order that specifies how its symbols are sorted and ordered. Some character sets also support alternative collation orders. In all cases, choice of character set limits choice of collation orders.

Available Character Sets and Collation Orders

Specifying a Default Character Set For a Database

Specifying a Character Set For a Column in a Table

Specifying a Character Set For a Client Connection

Specifying Collation Order For a Column

Specifying Collation Order in a Comparison Operation

Specifying Collation Order in an ORDER BY Clause

Specifying Collation Order in a GROUP BY Clause


Available Character Sets and Collation Orders

InterBase Character Sets and Collation Orders

Character Set Storage Requirements

Paradox and DBASE Character Sets and Collations

Microsoft Windows Character Sets

Additional Character Sets and Collations


InterBase Character Sets and Collation Orders

The following table lists each character set that can be used in InterBase. For each character set, the minimum and maximum number of bytes used to store each symbol is listed, and all collation orders supported for that character set are also listed. The first collation order for a given character set is that set's implicit collation, the one that is used if no COLLATE clause specifies an alternative order. The implicit collation order cannot be specified in the COLLATE clause.

Character Set	Set ID	Max. Size	Min. Size	Collation Orders

ASCII	2	1 byte	1 byte	ASCII
CYRL	50	1 byte	1 byte	CYRL DB_RUS PDOX_CYRL
DOS437	10	1 byte	1 byte	DOS437  DB_DEU437 DB_ESP437 DB_FIN437 DB_FRA437 DB_ITA437 DB_NLD437 DB_SVE437 DB_UK437 DB_US437 PDOX_ASCII PDOX_INTL PDOX_SWEDFIN
DOS850	11	1 byte	1 byte	DOS850  DB_DEU850 DB_ESP850 DB_FRA850 DB_FRC850 DB_ITA850 DB_NLD850 DB_PTB850 DB_SVE850 DB_UK850 DB_US850
DOS852	45	1 byte	1 byte	DOS852  DB_CSY  DB_PLK  DB_SLO  PDOX_CSY PDOX_HUN PDOX_PLK PDOX_SLO
DOS857	46	1 byte	1 byte	DOS857  DB_TRK
DOS860	13	1 byte	1 byte	DOS860  DB_PTG860
DOS861	47	1 byte	1 byte	DOS861  PDOX_ISL
DOS863	14	1 byte	1 byte	DOS863  DB_FRC863
DOS865	12	1 byte	1 byte	DOS865  DB_DAN865 DB_NOR865 PDOX_NORDAN4
EUCJ_0208	6	2 bytes	1 byte	EUJC_0208
ISO8859_1	21	1 byte	1 byte	ISO8859_1  DA_DA  DE_DE  DU_NL  EN_UK EN_US  ES_ES  FI_FI  FR_CA  FR_FR  IS_IS  IT_IT  NO_NO  PT_PT  SV_SV
NEXT	56	1 byte	1 byte	NEXT  NXT_DEU  NXT_FRA  NXT_ITA  NXT_US
NONE	0	1 byte	1 byte	NONE
OCTETS	1	1 byte	1 byte	OCTETS
SJIS_0208	5	2 bytes	1 byte	SJIS_0208
UNICODE_FSS	3	3 bytes	1 byte	UNICODE_FSS
WIN1250	51	1 byte	1 byte	WIN1250  PXW_CSY PXW_HUNDC PXW_PLK  PXW_SLO
WIN1251	52	1 byte	1 byte	WIN1251 PXW_CYRL
WIN1252	53	1 byte	1 byte	WIN1252  PXW_INTL PXW_INTL850 PXW_NORDAN4 PXW_SPAN PXW_SWEDFIN
WIN1253	54	1 byte	1 byte	WIN1253 PXW_GREEK
WIN1254	55	1 byte	1 byte	WIN1254 PXW_TURK


Character Set Storage Requirements

Knowing the storage requirements of a particular character set is important, because in the case of CHAR columns, InterBase restricts the maximum amount of storage in each field in the column to 32,767 bytes (VARCHAR is restricted to 32,765 bytes).

For character sets that require only a single byte of storage, the maximum number of symbols that can be stored in a single field corresponds to the number of bytes. For character sets that require up to three bytes per symbol, the maximum number of symbols that can be safely stored in a field is 1/3 of the maximum number of bytes for the data type. For example, for a CHAR column defines to use the UNICODE_FSS character set, the maximum number of characters that can be specified is 10,922 (32,767/3):

. . .

CHAR(10922) CHARACTER SET UNICODE_FSS,

. . .


Paradox and DBASE Character Sets and Collations

Many character sets and their corresponding collations are provided to support Borland Paradox for DOS, Paradox for Windows, dBASE for DOS, and dBASE for Windows.

Character Sets for DOS

The following character sets correspond to MS-DOS code pages, and should be used to specify character sets for InterBase databases that are accessed by Paradox for DOS and dBASE for DOS:

Character Set	DOS Code Page

DOS437	437

DOS850	850

DOS852	852

DOS857	857

DOS860	860

DOS861	861

DOS863	863

DOS865	865

The names of collation orders for these character sets that are specific to Paradox begin "PDOX". For example, the DOS865 character set for DOS code page 865 supports a Paradox collation order for Norwegian and Danish called "PDOX_NORDAN4".

The names of collation orders for these character sets that are specific to dBASE begin "DB". For example, the DOS437 character set for DOS code page 437 supports a dBASE collation order for Spanish called "DB_ESP437".

For more information about DOS code pages, and Paradox and dBASE collation orders, see the appropriate Paradox and dBASE documentation and driver books.


Microsoft Windows Character Sets

There are five character sets that support Windows client applications, such as Paradox for Windows. These character sets are: WIN1250, WIN1251, WIN1252, WIN1253, and WIN1254.

The names of collation orders for these character sets that are specific to Paradox for Windows begin "PXW". For example, the WIN125 character set supports a Paradox for Windows collation order for Norwegian and Danish called "PXW_NORDAN4".

For more information about Windows character sets and Paradox for Windows collation orders, see the appropriate Paradox for Windows documentation and driver books.


Additional Character Sets and Collations

Support for additional character sets and collation orders is constantly being added to InterBase. To see if additional character sets and collations are available for a newly created database, connect to the database with ISQL, then use the following set of queries to generate a list of available character sets and collations:

SELECT RDB$CHARACTER_SET_NAME, RDB$CHARACTER_SET_ID
FROM RDB$CHARACTER_SETS
ORDER BY RDB$CHARACTER_SET_NAME;

SELECT RDB$COLLATION_NAME, RDB$CHARACTER_SET_ID
FROM RDB$COLLATIONS
ORDER BY RDB$COLLATION_NAME;


Specifying a Default Character Set For a Database

A database's default character set designation specifies the character set the server uses to tag CHAR, VARCHAR, and text BLOB columns in the database when no other character set information is provided. When data is stored in such columns without additional character set information, the server uses the tag to determine how to store and transliterate that data. A default character set should always be specified for a database when it is created with CREATE DATABASE.

To specify a default character set, use the DEFAULT CHARACTER SET clause of CREATE DATABASE. For example, the following statement creates a database that uses the ISO8859_1 character set:

CREATE DATABASE "europe.gdb" DEFAULT CHARACTER SET ISO8859_1;

Important:	If you do not specify a character set, the character set defaults to NONE. Using character set NONE means that there is no character set assumption for columns; data is stored and retrieved just as you originally entered it. You can load any character set into a column defined with NONE, but you cannot later move that data into another column that has been defined with a different character set. In this case, no transliteration is performed between the source and destination character sets, and errors may occur during assignment.


Specifying a Character Set For a Column in a Table

Character sets for individual columns in a table can be specified as part of the column's CHAR or VARCHAR data type definition. When a character set is defined at the column level, it overrides the default character set declared for the database. For example, the following ISQL statements create a database with a default character set of ISO8859_1, then create a table where two column definitions include a different character set specification:

CREATE DATABASE "europe.gdb" DEFAULT CHARACTER SET ISO8859_1;

CREATE TABLE RUS_NAME(

LNAME VARCHAR(30) NOT NULL CHARACTER SET CYRL,

FNAME VARCHAR(20) NOT NULL CHARACTER SET CYRL,

);


Specifying a Character Set For a Client Connection

When a client application, such as ISQL, connects to a database, it may have its own character set requirements. The server providing database access to the client does not know about these requirements unless the client specifies them. The client application specifies its character set requirement using the SET NAMES statement before it connects to the database.

SET NAMES specifies the character set the server should use when translating data from the database to the client application. Similarly, when the client sends data to the database, the server translates the data from the client's character set to the database's default character set (or the character set for an individual column if it differs from the database's default character set).

For example, the following ISQL command specifies that ISQL is using the DOS437 character set. The next command connects to the europe database created above, in "Specifying a Character Set for a Column in a Table":

SET NAMES DOS437;

CONNECT "europe.gdb" USER "JAMES" PASSWORD "U4EEAH";


Specifying Collation Order For a Column

When a CHAR or VARCHAR column is created for a table, either with CREATE TABLE or ALTER TABLE, the collation order for the column can be specified using the COLLATE clause. COLLATE is especially useful for character sets such as ISO8859_1 or DOS437 that support many different collation orders.

For example, the following ISQL ALTER TABLE statement adds a new column to a table, and specifies both a character set and a collation order:

ALTER TABLE "FR_CA_EMP"

ADD ADDRESS VARCHAR(40) CHARACTER SET ISO8859_1 NOT NULL
COLLATE FR_CA;


Specifying Collation Order in a Comparison Operation

When CHAR or VARCHAR values are compared in a WHERE clause, it can be necessary to specify a collation order for the comparisons if the values being compared use different collation orders.

To specify the collation order to use for a value during a comparison, include a COLLATE clause after the value. For example, in the following WHERE clause fragment from an embedded application, the value to the left of the comparison operator is forced to be compared using a specific collation:

WHERE LNAME COLLATE FR_CA = :lname_search;


Specifying Collation Order in an ORDER BY Clause

When CHAR or VARCHAR columns are ordered in a SELECT statement, it can be necessary to specify a collation order for the ordering, especially if columns used for ordering use different collation orders.

To specify the collation order to use for ordering a column in the ORDER BY clause, include a COLLATE clause after the column name. For example, in the following ORDER BY clause, the collation order for two columns is specified:

. . .

ORDER BY LNAME COLLATE FR_CA, FNAME COLLATE FR_CA;


Specifying Collation Order in a GROUP BY Clause

When CHAR or VARCHAR columns are grouped in a SELECT statement, it can be necessary to specify a collation order for the grouping, especially if columns used for grouping use different collation orders.

To specify the collation order to use for grouping columns in the GROUP BY clause, include a COLLATE clause after the column name. For example, in the following GROUP BY clause, the collation order for two columns is specified:

. . .

GROUP BY LNAME COLLATE FR_CA, FNAME COLLATE FR_CA;


Working With Indexes

Index Basics

How to Create Indexes

How to Improve Index Performance

How to Alter Indexes

How to Drop Indexes


Index Basics

An index is a mechanism that is used to speed the retrieval of records in response to certain search conditions, and to enforce uniqueness constraints on columns. Just as you search an index in a book for a list of page numbers to quickly find the pages that you want to read, a database index serves as a logical pointer to the physical location (address) of a row in a table. An index stores each value of the indexed column or columns along with pointers to all of the disk blocks that contain rows with that column value.

When executing a query, the InterBase engine first checks to see if any indexes exist for the named tables. It then determines whether it is more efficient to scan the entire table, or to use an existing index to process the query. If the engine decides to use an index, it searches the index to find the key values requested, and follows the pointers to locate the rows in the table containing the values.

Data retrieval is fast because the values in the index are ordered, and the index is relatively small. This allows the system to quickly locate the key value. Once the key value is found, the system follows the pointer to the physical location of the associated data. Using an index typically requires fewer page fetches than a sequential read of every row in the table.

An index can be defined on a single column or on multiple columns of a table. Multi-column indexes can be used for single-column lookups, as long as the column that is being retrieved is the first in the index.

When to Index

An index on a column can mean the difference between an immediate response to a query and a long wait, as the length of time it takes to search the whole table is directly proportional to the number of rows in the table. So why not index every column? The main drawbacks are that indexes consume additional disk space, and inserting, deleting, and updating data takes longer on indexed columns than on non-indexed columns. The reason is that the index must be updated each time the data in the indexed column changes, and each time a row is added to or deleted from the table.

Nevertheless, the overhead of indexes is usually outweighed by the boost in performance for data retrieval queries. You should create an index on a column when:

Search conditions frequently reference the column.

Join conditions frequently reference the column.

ORDER BY statements frequently use the column to sort data.

You do not need to create an index for:

Columns that are seldom referenced in search conditions.

Frequently updated non-key columns.

Columns that have a small number of possible values.


How to Create Indexes

Indexes are either created by the user with the CREATE INDEX statement, or they are created automatically by the system as part of the CREATE TABLE statement. InterBase allows users to create as many as 64 indexes on a given table. To create indexes you must have authority to connect to the database.

Note:	To see all indexes defined for the current database, use the ISQL command SHOW INDEX. To see all indexes defined for a specific table, use the command, SHOW INDEX tablename. To view information about a specific index, use SHOW INDEX indexname.

InterBase automatically generates system-level indexes on a column or set of columns when tables are defined using PRIMARY KEY, FOREIGN KEY, and UNIQUE constraints. Indexes on PRIMARY KEY and FOREIGN KEY constraints preserve referential integrity.

Using CREATE INDEX

Multi-column Indexes


Using CREATE INDEX

The CREATE INDEX statement creates an index on one or more columns of a table. A single-column index searches only one column in response to a query, while a multi-column index searches one or more columns. Options specify:

Whether duplicate entries are allowed in the indexed column.

The sort order for the index.

Use CREATE INDEX to improve speed of data access. For faster response to queries that require sorted values, use the index order that matches the query's ORDER BY clause. Use an index for columns that appear in a WHERE clause to speed searching.

To improve index performance, use SET STATISTICS to recompute index selectivity, or rebuild the index by making it inactive, then active with sequential calls to ALTER INDEX.

The syntax for CREATE INDEX is:

CREATE [UNIQUE] [ASC[ENDING] | DESC[ENDING]]
INDEX index ON table (col [, col ...]);

The complete syntax of CREATE INDEX is in the online SQL Reference.


Preventing Duplicate Entries

No two rows can be alike when a UNIQUE index is specified for a column or set of columns. The system checks for duplicate values when the index is created, and each time a row is inserted or updated. InterBase automatically creates a UNIQUE index on a PRIMARY KEY column, forcing the values in that column to be unique identifiers for the row. Unique indexes only make sense when uniqueness is a characteristic of the data itself. For example, you would not define a unique index on a LAST_NAME column because there is a high probability for duplication. Conversely, a unique index is a good idea on a column containing a social security number.

To define an index that disallows duplicate entries, include the UNIQUE keyword in CREATE INDEX. The following statement creates a unique ascending index (PRODTYPEX) on the PRODUCT and PROJ_NAME columns of the PROJECT table:

CREATE UNIQUE INDEX PRODTYPEX ON PROJECT (PRODUCT, PROJ_NAME);

Tip:	InterBase does not allow a unique index to be created on a column that already contains duplicate values. Before defining a UNIQUE index, use a SELECT statement to ensure there are no duplicate keys in the table. For example:

SELECT PRODUCT, PROJ_NAME FROM PROJECT
GROUP BY PRODUCT, PROJ_NAME
HAVING COUNT(*) > 1;


Specifying Index Sort Order

Specify a direction (low to high or high to low) by using the ASCENDING or DESCENDING keyword. By default, InterBase creates indexes in ascending order. To make a descending index on a column or group of columns, use the DESCENDING keyword to define the index. The following statement creates a descending index (DESC_X) on the CHANGE_DATE column of the SALARY_HISTORY table:

CREATE DESCENDING INDEX DESC_X ON SALARY_HISTORY (CHANGE_DATE);

Note:	To retrieve indexed data from this table in descending order, use ORDER BY CHANGE_DATE DESCENDING in the SELECT statement.

If you intend to use both ascending and descending sort orders on a particular column, define both an ascending and a descending index for the same column. The following example illustrates this:

CREATE ASCENDING INDEX ASCEND_X ON SALARY_HISTORY (CHANGE_DATE);

CREATE DESCENDING INDEX DESC_X ON SALARY_HISTORY (CHANGE_DATE);


Multi-column Indexes

Examples

The main reason to use a multi-column index is to speed up queries that often access the same set of columns. You do not have to create the query with the exact column list that is defined in the index. InterBase will use a subset of the components of a multi-column index to optimize a query if the:

Subset of columns used in the ORDER BY clause begins with the first column in the multi-column index. Unless the query uses all prior columns in the list, InterBase cannot use that index to optimize the search. For example, if the index column list is A1, A2, and A3, a query using A1 and A2 would be optimized using the index, but a query using A2 and A3 would not.

Order in which the query accesses the columns in an ORDER BY clause matches the order of the column list defined in the index. (The query would not be optimized if its column list were A2, A1.)

Tip:	Because of the way InterBase optimizes queries on multi-column indexes, it is better to create several single-column indexes when you expect to issue frequent search conditions against a table using the OR operator. Because it is likely that some columns that were indexed using a multi-column index will be excluded when applying the OR operator in a WHERE clause, the optimizer will scan the entire table if there are no other single-column indexes available.


Examples Using Multi-column Indexes

The first example creates a multi-column index, NAMEX, on the EMPLOYEE table:

CREATE INDEX NAMEX ON EMPLOYEE (LAST_NAME, FIRST_NAME);

The following query will be optimized against the index because the ORDER BY clause references all of the indexed columns in the correct order:

SELECT LAST_NAME, SALARY FROM EMPLOYEE

WHERE SALARY > 40000

ORDER BY LAST_NAME, FIRST_NAME;

The next query will also process the following query with an index search (using LAST_NAME from NAMEX) because although the ORDER BY clause only references one of the indexed columns (LAST_NAME), it does so in the correct order.

SELECT LAST_NAME, SALARY FROM EMPLOYEE

WHERE SALARY > 40000

ORDER BY LAST_NAME;

Conversely, the following query will not be optimized against the index because the ORDER BY clause uses FIRST_NAME, which is not the first indexed column in the NAMEX column list.

SELECT LASTNAME, SALARY FROM EMP

WHERE SALARY > 40000

ORDER BY FIRST_NAME;

The same rules that apply to the ORDER BY clause also apply to queries containing a WHERE clause. The next example creates a multi-column index for the PROJECT table:

CREATE UNIQUE INDEX PRODTYPEX ON PROJECT (PRODUCT, PROJ_NAME);

The following query will be optimized against the PRODTYPEX index because the WHERE clause references the first indexed column (PRODUCT) of the index:

SELECT * FROM PROJECT

WHERE PRODUCT ="software";

Conversely, the next query will not be optimized against the index because PROJ_NAME is not the first indexed column in the column list of the PRODTYPEX index:

SELECT * FROM PROJECT

WHERE PROJ_NAME ="InterBase 4.0";


How to Improve Index Performance

Indexes can become unbalanced after many changes to the database. When this happens, performance can be improved using one of the following methods:

1.	Rebuild the index with ALTER INDEX.

2.	Recompute index selectivity with SET STATISTICS.

3.	Delete and recreate the index with DROP INDEX and CREATE INDEX.


How to Alter Indexes

The ALTER INDEX statement deactivates and reactivates an index. Deactivating and reactivating an index is useful when changes in the distribution of indexed data cause the index to become unbalanced. To rebuild the index, first use ALTER INDEX INACTIVE to deactivate the index, then ALTER INDEX ACTIVE to reactivate it again. This method recreates and balances the index.

Tip:	Before inserting a large number of rows, deactivate a table's indexes during the insert, then reactivate the index to rebuild it. Otherwise, InterBase will incrementally update the index each time a single row is inserted.

The syntax for ALTER INDEX is:

ALTER INDEX name {ACTIVE | INACTIVE};

The following statements deactivate and reactivate an index to rebuild it:

ALTER INDEX BUDGETX INACTIVE;

ALTER INDEX BUDGETX ACTIVE;

The complete syntax of ALTER INDEX is in the online SQL Reference.

Restrictions

The following restrictions apply to altering an index:

In order to alter an index, you must be the creator of the index, a SYSDBA user, or a user with operating system root privileges.

You cannot alter an index if it is in use in an active database. An index is in use if it is currently being used by a compiled request to process a query. All requests using an index must be released to make it available.

You cannot alter an index that has been defined with a UNIQUE, PRIMARY KEY, or FOREIGN KEY constraint. If you want to modify the constraints, you must use ALTER TABLE.

You cannot use ALTER INDEX to add or drop index columns or keys. Use DROP INDEX to delete the index and then redefine it with CREATE INDEX.


Using SET STATISTICS

For tables where the number of duplicate values in indexed columns radically increases or decreases, periodically recomputing index selectivity can improve performance. SET STATISTICS recomputes the selectivity of an index.

Index selectivity is a calculation that is made by the InterBase optimizer when a table is accessed, and is based on the number of distinct rows in a table. It is cached in memory, where the optimizer can access it to calculate the optimal retrieval plan for a given query.

The syntax for SET STATISTICS is:

SET STATISTICS INDEX name;

The following statement recomputes the selectivity for an index:

SET STATISTICS INDEX MINSALX;

Restrictions

The following restrictions apply to the SET STATISTICS statement:

In order to use SET STATISTICS, you must be the creator of the index, a SYSDBA user, or a user with operating system root privileges.

SET STATISTICS does not rebuild an index. To rebuild an index, use ALTER INDEX.


How to Drop Indexes

DROP INDEX removes a user-defined index from the database. System-defined indexes, such as those created on columns defined with UNIQUE, PRIMARY KEY, and FOREIGN KEY constraints cannot be dropped.

To alter an index, first use the DROP INDEX statement to delete the index, then use the CREATE INDEX statement to recreate the index (using the same name) with the desired characteristics.

The syntax for DROP INDEX is:

DROP INDEX name;

The following statement deletes an index:

DROP INDEX MINSALX;

Restrictions

The following restrictions apply to dropping an index:

To drop an index, you must be the creator of the index, a SYSDBA user, or a user with operating system root privileges.

An index in use cannot be dropped until it is no longer in use. If you try to alter or drop an index while transactions are being processed, the results depend on the type of transaction in operation. In a WAIT transaction, the ALTER INDEX or DROP INDEX operation waits until the index is not in use. In a NOWAIT transaction, InterBase returns an error.

If an index was automatically created by the system on a column having a UNIQUE, PRIMARY KEY, or FOREIGN KEY constraint, you cannot drop the index. To drop an index on a column defined with those constraints, drop the constraint, the constrained column, or the table. To modify the constraints, use ALTER TABLE.


Working With Views

View Basics

How to Create Views

How to Insert Data Through a View

How to Drop Views


View Basics

Database users typically need to access a particular subset of the data that is stored in the database. Further, the data requirements within an individual user or group are often quite consistent. Views provide a way to create a customized version of the underlying tables that display only the clusters of data that a given user or group of users is interested in.

Once a view is defined, you can display and operate on it as if it were an ordinary table. A view can be derived from one or more tables, or from another view. Views look just like ordinary database tables, but they are not physically stored in the database. The database stores only the view definition, and uses this definition to filter the data when a query referencing the view occurs.

Important:	It is important to understand that creating a view does not generate a copy of the data stored in another table; when you change the data through a view, you are changing the actual data in the underlying tables. Conversely, when the data in the base tables is changed directly, the views that were derived from the base tables are automatically updated to reflect the changes. Think of a view as a movable "window" or frame through which you can see the actual data. The data definition is the "frame."

A view can be created with:

A vertical subset of columns from a single table. For example, the table, JOB, in the employee.gdb database has 8 columns: JOB_CODE, JOB_GRADE, JOB_COUNTRY, JOB_TITLE, MIN_SALARY, MAX_SALARY, JOB_REQUIREMENT, and LANGUAGE_REQ. The following view displays a list of salary ranges (subset of columns) for all jobs (all rows) in the JOB table:

CREATE VIEW JOB_SALARY_RANGES AS
SELECT JOB_CODE, MIN_SALARY, MAX_SALARY
FROM JOB;

A horizontal subset of rows from a single table. The next view displays all of the columns in the JOB table, but only the subset of rows where the MAX_SALARY is less than $15,000:

CREATE VIEW LOW_PAY AS
SELECT *
FROM JOB
WHERE MAX_SALARY < 15000;

A combined vertical and horizontal subset of columns and rows from a single table. The next view displays only the JOB_CODE and JOB_TITLE columns and only those jobs where MAX_SALARY is less than $15,000:

CREATE VIEW ENTRY_LEVEL_JOBS AS
SELECT JOB_CODE, JOB_TITLE,
FROM JOB
WHERE MAX_SALARY < 15000;

A subset of rows and columns from multiple tables (joins). The next example shows a view created from both the JOB and EMPLOYEE tables. The EMPLOYEE table contains 11 columns: EMP_NO, FIRST_NAME, LAST_NAME, PHONE_EXT, HIRE_DATE, DEPT_NO, JOB_CODE, JOB_GRADE, JOB_COUNTRY, SALARY, FULL_NAME. It displays two columns from the JOB table, and two columns from the EMPLOYEE table, and returns only the rows where SALARY is less than $15,000:

CREATE VIEW ENTRY_LEVEL_WORKERS AS
SELECT JOB_CODE, JOB_TITLE, FIRST_NAME, LAST_NAME
FROM JOB, EMPLOYEE
WHERE JOB.JOB_CODE = EMPLOYEE.JOB_CODE AND SALARY < 15000;

Advantages of Views

The main advantages of views are:

Simplified access to the data. Views enable you to encapsulate a subset of data from one or more tables to use as a foundation for future queries without requiring you to repeat the same set of SQL statements to retrieve the same subset of data.

Customized access to the data. Views provide a way to tailor the database to suit a variety of users with dissimilar skills and interests. You can focus on the information that specifically concerns you without having to process extraneous data.

Data independence. Views protect users from the effects of changes to the underlying database structure. For example, if the database administrator decides to split one table into two, a view can be created that is a join of the two new tables, thus shielding the users from the change.

Data security. Views provide security by restricting access to sensitive or irrelevant portions of the database. For example, you might be able to look up job information, but not be able to see associated salary information.


How to Create Views

The CREATE VIEW statement creates a virtual table based on one or more underlying tables in the database. You can perform select, project, join, and union operations on views just as if they were tables.

The user who creates a view is its owner and has all privileges for it, including the ability to GRANT privileges to other users, triggers, and stored procedures. A user can be granted privileges to a view without having access to its base tables.

The syntax for CREATE VIEW is:

CREATE VIEW name [(view_col [, view_col ...])]
AS <select> [WITH CHECK OPTION];

The complete syntax of CREATE VIEW is in the online SQL Reference.

Specifying View Column Names

Using the SELECT Statement

Using Expressions to Define Columns

Types of Views: Read-only and Updatable


Specifying View Column Names

view_col names one or more columns for the view. Column names are optional unless the view includes columns based on expressions. When specified, view column names correspond in order and number to the columns listed in <select>, so you must specify view column names for every column selected, or do not specify names at all.

Column names must be unique among all column names in the view. If column names are not specified, the view takes the column names from the underlying table by default.

If the view definition includes an expression, view_col names are required. A view_col definition can contain one or more columns based on an expression.

Note:	ISQL does not support view definitions containing UNION clauses. You must write an embedded application to create this type of view.


Using the SELECT Statement

The SELECT statement specifies the selection criteria for the rows to be included in the view. SELECT does the following:

Lists the columns to be included from the base table. When SELECT * is used rather than a column list, the view contains all of the column names from the base table, and displays them in the order in which they appear in the base table. The following example creates a view, MY_VIEW, that contains all of the columns in the EMPLOYEE table:

CREATE VIEW MY_VIEW AS
SELECT * FROM EMPLOYEE;

Identifies the source tables in the FROM clause. In the MY_VIEW example, EMPLOYEE is the source table.

Specifies, if needed, row selection conditions in a WHERE clause. In the next example, only the employees that work in the USA are included in the view:

CREATE VIEW USA_EMPLOYEES AS
SELECT * FROM EMPLOYEE
WHERE JOB_COUNTRY = "USA";

If WITH CHECK OPTION is specified, it prevents INSERT or UPDATE operations on an updatable view if the operation violates the search condition specified in the WHERE clause.

Important:	When creating views, the SELECT statement cannot include an ORDER BY clause.


Using Expressions to Define Columns

An expression can be any SQL statement that performs a comparison or computation, and returns a single value. Examples of expressions are concatenating character strings, performing computations on numeric data, doing comparisons using comparison operators (<, >, <=, and so on) or Boolean operators (AND, OR, NOT). The expression must return a single value, and cannot be an array or return an array. Any columns used in the value expression must exist before the expression can be defined.

For example, suppose you want to create a view that displays the salary ranges for all jobs that pay at least $60,000. The view, GOOD_JOB, based on the JOB table, selects the pertinent jobs and their salary ranges:

CREATE VIEW GOOD_JOB (JOB_TITLE, STRT_SALARY, TOP_SALARY) AS
SELECT JOB_TITLE, MIN_SALARY, MAX_SALARY FROM JOB
WHERE MIN_SALARY > 60000;

Suppose you want to create a view that assigns a hypothetical 10% salary increase to all employees in the company. The next example creates a view that displays all of the employees and their new salaries:

CREATE VIEW 10%_RAISE (EMPLOYEE, NEW_SALARY) AS
SELECT EMP_NO, SALARY *1.1 FROM EMPLOYEE;

Note:	Remember, unless the creator of the view assigns INSERT or UPDATE privileges, the users of the view cannot affect the actual data in the underlying table.


Types of Views: Read-only and Updatable

Examples

Although you can create many kinds of views, there are some restrictions on updating data through views which depend upon the type of query used to define the view. A view can be either updatable or read-only.

Note:	The terms updatable and read-only refer to how you access the data in the underlying tables, not modifications to the view definition itself. To modify the view itself, you must drop the view and then recreate it.

A view is updatable if all of the following conditions are met:

It is a subset of a single table or another updatable view.

All base table columns excluded from the view definition allow NULL values.

The view's SELECT statement does not contain subqueries, a DISTINCT predicate, a HAVING clause, aggregate functions, joined tables, user-defined functions, or stored procedures.

If the view definition does not meet all of these conditions, it is considered read-only.

Note:	Read-only views can be updated by using a combination of user-defined referential constraints, triggers, and unique indexes.

View Privileges

The creator of the view must have the following privileges:

To create a read-only view, the creator needs SELECT privileges for any underlying tables.

To create an updatable view, the creator needs ALL privileges to the underlying tables.


Examples of Read-only vs. Updatable Views

The following statement creates an updatable view:

CREATE VIEW EMP_MNGRS (FIRST, LAST, SALARY) AS
SELECT FIRST_NAME, LAST_NAME, SALARY
FROM EMPLOYEE
WHERE JOB_CODE = "Mngr";

The next statement uses a nested query to create a view, so the view is read-only:

CREATE VIEW ALL_MNGRS AS
SELECT FIRST_NAME, LAST_NAME, JOB_COUNTRY FROM EMPLOYEE WHERE JOB_COUNTRY IN (SELECT JOB_COUNTRY FROM JOB
WHERE JOB_TITLE = "manager");

The next statement creates a view that joins two tables, and so it is also read-only:

CREATE VIEW PHONE_LIST AS SELECT
EMP_NO, FIRST_NAME, LAST_NAME, PHONE_EXT, LOCATION, PHONE_NO
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.DEPT_NO = DEPARTMENT.DEPT_NO.


How to Insert Data Through a View

Rows can be inserted and updated through a view if the following conditions are met:

The view is updatable.

A user or stored procedure has INSERT privilege for the view.

The view is created using WITH CHECK OPTION.

Using WITH CHECK OPTION

WITH CHECK OPTION specifies rules for modifying data through views. This option can be included only if the views are updatable. Views that are created using WITH CHECK OPTION enable InterBase to verify that a row inserted or updated through a view can be seen through the view before allowing the operation to succeed. Values can only be inserted through a view for those columns named in the view. InterBase stores NULL values for unreferenced columns.

WITH CHECK OPTION prevents you from inserting or updating values that do not satisfy the search condition specified in the WHERE clause of the CREATE VIEW <select> statement.

For example, suppose you wanted to create a view that allowed access to information about all departments with budgets between $10,000 and $500,000. The view, SUB_DEPT, is defined as follows:

CREATE VIEW SUB_DEPT
(DEPT_NAME, DEPT_NO, SUB_DEPT_NO, LOW_BUDGET)
AS SELECT DEPARTMENT, DEPT_NO, HEAD_DEPT, BUDGET
FROM DEPARTMENT WHERE BUDGET BETWEEN 10000 AND 500000
WITH CHECK OPTION;

The SUB_DEPT view references a single table, DEPARTMENT. If you are the creator of the view, and/or have INSERT privileges, you can insert new data into the DEPARTMENT, DEPT_NO, HEAD_DEPT, and BUDGET columns of the base table, DEPARTMENT. WITH CHECK OPTION assures that all values entered through the view fall within the range prescribed for each column in the WHERE clause of the SUB_DEPT view.

The following statement inserts a new row for the Publications Department through the SUB_DEPT view:

INSERT INTO SUB_DEPT (DEPT_NAME, DEPT_NO, SUB_DEPT_NO, LOW_BUDGET)
VALUES ("Publications", "7735", "670", 250000);

InterBase inserts NULL values for all other columns in the DEPARTMENT base table that are not available directly through the view.


How to Drop Views

The DROP VIEW statement enables a view's creator to remove a view definition from the database. It does not affect the base tables associated with the view. You can drop a view only if:

You created the view.

The view is not used in another view, a stored procedure, or CHECK constraint definition. You must delete the associated database objects before dropping the view.

The syntax for DROP VIEW is:

DROP VIEW name;

The following statement removes a view definition:

DROP VIEW SUB_DEPT;

Note:	You cannot directly alter a view. To change it, drop the view and use the CREATE VIEW statement to recreate a view with the same name and the features you want.


Working With Stored Procedures

Stored Procedure Basics

How to Use Stored Procedures

How to Create Procedures

How to Alter Procedures

How to Drop Procedures

Working With Exceptions

How to Handle Errors


Stored Procedures Basics
Stored Procedure Basics

A stored procedure is a self-contained program written in InterBase procedure and trigger language, and stored as part of a the database metadata.

Once you have created a stored procedure, you can invoke it directly from an application, or substitute the procedure for a table or view in a SELECT statement. Stored procedures can receive input parameters from and return values to applications.

InterBase procedure and trigger language includes SQL data manipulation statements and some powerful extensions, including IF . . . THEN . . . ELSE, WHILE . . . DO, FOR SELECT . . . DO, exceptions, and error handling.

The advantages of using stored procedures include:

Modular design.

Stored procedures may be shared by applications that access the same database, eliminating duplicate code, and reducing the size of applications.

Streamlined maintenance.

When a procedure is updated, the changes are automatically reflected in all applications that use it without the need to recompile and relink them. Applications are compiled and optimized only once for each client.

Improved performance.

Stored procedures are executed by the server, not the client, which reduces network traffic, and improves performance--especially for remote client access.

There are two ways to create, alter, and drop procedures with ISQL:

Interactively

With an input file containing data definition statements

It is usually preferable to use data definition files, because they are easier to modify and provide separate documentation of the procedure. For simple changes to existing procedures or exceptions, the interactive interface can be convenient.

The user who creates a procedure is the owner of the procedure, and can grant the privilege to execute the procedure to other users, triggers, and stored procedures.

Using a Data Definition File

Calling Stored Procedures

Privileges for Stored Procedures


Using a Data Definition File

To create or alter a procedure through a data definition file, create an ISQL script and process it using Windows ISQL.

If you do not specify the database on the command line or interactively, the data definition file must include a statement to create or open a database.

The data definition file can include:

Statements to create, alter, or drop procedures. The file can also include statements to create, alter, or drop exceptions. Exceptions must be created before they can be referenced in procedures.

Any other ISQL statements.


Calling Stored Procedures

Applications can call stored procedures from SQL and DSQL. You can also use stored procedures in ISQL.

There are two types of stored procedures:

Select procedures that an application can use in place of a table or view in a SELECT statement. A select procedure must be defined to return one or more values (output parameters), or an error results.

Executable procedures that an application can call directly with the EXECUTE PROCEDURE statement. An executable procedure may or may not return values to the calling program.

Both kinds of procedures are defined with CREATE PROCEDURE and have essentially the same syntax. The difference is in how the procedure is written and how it is intended to be used. Select procedures can return more than one row, so that to the calling program they appear as a table or view. Executable procedures are routines invoked by the calling program, which may or may not return values.

In fact, a single procedure conceivably can be used as a select procedure or as an executable procedure, but in general a procedure is written specifically to be used in a SELECT statement (a select procedure) or to be used in an EXECUTE PROCEDURE statement (an executable procedure).


Privileges For Stored Procedures

To use a stored procedure, a user must be the creator of the procedure or must be given EXECUTE privilege for it. An extension to the GRANT statement assigns the EXECUTE privilege, and an extension to the REVOKE statement eliminates the privilege.

Stored procedures themselves sometimes need access to tables or views for which a user does not--or should not--have privileges.


How to Use Stored Procedures

Stored procedures can be used in applications in a variety of ways. Select procedures are used in place of a table or view in a SELECT statement. Executable procedures are used with an EXECUTE PROCEDURE statement.

Both kinds of procedures are defined with CREATE PROCEDURE and have the same syntax. The difference is in how the procedure is written and how it is intended to be used. Select procedures always return one or more rows, so that to the calling program they appear as a table or view. Executable procedures are simply routines invoked by the calling program which may or may not return values.

In fact, a single procedure can be used as a select procedure or an executable procedure, but this is not recommended. A procedure should be written specifically to be used in a SELECT statement (a select procedure) or to be used in an EXECUTE PROCEDURE statement (an executable procedure).

During application development, create and test stored procedures in ISQL. Once a stored procedure has been created, tested, and refined, it can be used in applications.


Using Executable Procedures in ISQL
Using Executable Procedures in Windows ISQL

An executable procedure is invoked with EXECUTE PROCEDURE. It may return at most one row. To execute a stored procedure in ISQL, use the following syntax:

EXECUTE PROCEDURE name [(] [param [, param ...]] [)];

The procedure name must be specified, and each param is an input parameter value (a constant). All input parameters required by the procedure must be supplied.

Important:	In ISQL, do not supply output parameters or use RETURNING_VALUES in the EXECUTE PROCEDURE statement, even if the procedure returns values. ISQL automatically displays output parameters.

To execute the procedure, DEPT_BUDGET, from ISQL, use:

EXECUTE PROCEDURE DEPT_BUDGET 110;

ISQL displays this output:

 TOT

====================

 1700000.00


Using Select Procedures in ISQL
Using Select Procedures in Windows ISQL

A select procedure is used in place of a table or view in a SELECT statement and can return a single row or multiple rows.

The advantages of select procedures over tables or views are:

They can take input parameters that can affect the output.

They can contain logic not available in normal queries or views.

They can return rows from multiple tables using UNION.

The syntax of SELECT from a procedure is:

SELECT <col_list> from name ([param [, param ...]])

WHERE <search_condition>

ORDER BY <order_list>;

The complete syntax of SELECT is in the online SQL Reference.

The procedure name must be specified, and in ISQL each param is a constant passed to the corresponding input parameter. All input parameters required by the procedure must be supplied. The <col_list> is a comma-delimited list of output parameters returned by the procedure, or * to select all rows.

The WHERE clause specifies a <search_condition> that selects a subset of rows to return. The ORDER BY clause specifies how to order the rows returned.

For example, the following code defines the procedure, GET_EMP_PROJ that returns proj_id, the project numbers to which an employee is assigned. It takes the employee number, emp_no, as the input parameter.

SET TERM !! ;

CREATE PROCEDURE GET_EMP_PROJ (EMP_NO SMALLINT)

RETURNS (PROJ_ID CHAR(5)) AS

BEGIN

FOR SELECT PROJ_ID

FROM EMPLOYEE_PROJECT

WHERE EMP_NO = :emp_no

INTO :proj_id

DO

SUSPEND;

END !!

The following statement selects from GET_EMP_PROJ in ISQL:

SELECT * FROM GET_EMP_PROJ(24);

The output is:

PROJ_ID

=======

DGPII

GUIDE

The following select procedure, ORG_CHART, displays an organizational chart:

CREATE PROCEDURE ORG_CHART

RETURNS (HEAD_DEPT CHAR(25), DEPARTMENT CHAR(25),

MNGR_NAME CHAR(20), TITLE CHAR(5), EMP_CNT INTEGER)

AS

DECLARE VARIABLE mngr_no INTEGER;

DECLARE VARIABLE dno CHAR(3);

BEGIN

FOR SELECT H.DEPARTMENT, D.DEPARTMENT, D.MNGR_NO, D.DEPT_NO

FROM DEPARTMENT D

LEFT OUTER JOIN DEPARTMENT H ON D.HEAD_DEPT = H.DEPT_NO

ORDER BY D.DEPT_NO

INTO :head_dept, :department, :mngr_no, :dno

DO

BEGIN

IF (:mngr_no IS NULL) THEN

BEGIN

mngr_name = "--TBH--";

title = "";

END

ELSE

SELECT FULL_NAME, JOB_CODE

FROM EMPLOYEE

WHERE EMP_NO = :mngr_no

INTO :mngr_name, :title;

SELECT COUNT(EMP_NO)

FROM EMPLOYEE

WHERE DEPT_NO = :dno

INTO :emp_cnt;

SUSPEND;

END

END !!

ORG_CHART is invoked from ISQL as follows:

SELECT * FROM ORG_CHART;

For each department, the procedure will display the department name, the department's "head department" (managing department), the department manager's name and title, and the number of employees in the department.

HEAD_DEPT	DEPARTMENT	MNGR_NAME 	TITLE	EMP_CNT

==============	==============	================	=====	======

Corporate HQ	Bender, Oliver 	CEO 	2

Corporate HQ	Sales and Mktg	MacDonald, Mary 	VP	2

Sales and Mktg	Pacific Rim HQ	Baldwin, Janet	Sales	2

Pacific Rim HQ	Japan	Yamamoto, Takashi	SRep 	2

Pacific Rim HQ	Singapore	--TBH--	0

ORG_CHART must be used as a select procedure to display the full organization. If called with EXECUTE PROCEDURE, then the first time it encounters the SUSPEND statement, the procedure terminates, returning the information for Corporate Headquarters only.

SELECT can specify columns to retrieve from a procedure. For example, if ORG_CHART is invoked as follows:

SELECT DEPARTMENT FROM ORG_CHART;

then only the second column, DEPARTMENT, is displayed.

Using WHERE and ORDER BY Clauses

A SELECT from a stored procedure can contain WHERE and ORDER BY clauses, just as in a SELECT from a table or view.

The WHERE clause limits the results returned by the procedure to rows matching the search condition. For example, the following statement returns only those rows where the HEAD_DEPT is Sales and Marketing:

SELECT * FROM ORG_CHART WHERE HEAD_DEPT = "Sales and Marketing";

The stored procedure then returns only the matching rows, for example:

HEAD_DEPT	DEPARTMENT	MNGR_NAME	TITLE	EMP_CNT

==============	==============	==============	=====	======

Sales and Mktg	Pacific Rim HQ	Baldwin, Janet	Sales	2

Sales and Mktg	European HQ	Reeves, Roger	Sales	3

Sales and Mktg	East Coast	Weston, K. J.	SRep	2

The ORDER BY clause can be used to order the results returned by the procedure. For example, the following statement orders the results by EMP_CNT, the number of employees in each department, in ascending order (the default):

SELECT * FROM ORG_CHART ORDER BY EMP_CNT;

Selecting Aggregates From Procedures

In addition to selecting values from a procedure, you can use aggregate functions. For example, to use ORG_CHART to display a count of the number of departments, use the following statement:

SELECT COUNT(DEPARTMENT) FROM ORG_CHART;

The results are:

 	COUNT

============

 	24

Similarly, to use ORG_CHART to display the maximum and average number of employees in each department, use the following statement:

SELECT MAX(EMP_CNT), AVG(EMP_CNT) FROM ORG_CHART;

The results are:

 	MAX 	AVG

========== 	=========

 	 5 	 2

Caution:	If a procedure encounters an error or exception, the aggregate functions do not return the correct values, since the procedure terminates before all rows are processed.


How to Create Stored Procedures

You can define a stored procedure with the CREATE PROCEDURE statement in ISQL. You cannot create stored procedures in embedded SQL. A stored procedure is composed of a header and a body.

The header contains:

The name of the stored procedure, which must be unique among procedure, view, and table names in the database.

An optional list of input parameters and their data types that a procedure receives from the calling program.

If the procedure returns values to the calling program, RETURNS followed by a list of output parameters and their data types.

The procedure body contains:

An optional list of local variables and their data types.

A block of statements in InterBase procedure and trigger language, bracketed by BEGIN and END. A block can itself include other blocks, so that there can be many levels of nesting.

Important:	Because each statement in a stored procedure body must be terminated by a semicolon, you must define a different symbol to terminate the CREATE PROCEDURE statement in ISQL. Use SET TERM before CREATE PROCEDURE to specify a terminator other than a semicolon. After the CREATE PROCEDURE statement, include another SET TERM to change the terminator back to a semicolon.

CREATE PROCEDURE Syntax

CREATE PROCEDURE name

[(param datatype [, param datatype ...])]
[RETURNS (param datatype [, param datatype ...])]
AS
<procedure_body>;

<procedure_body> =
[<variable_declaration_list>]
<block>

<variable_declaration_list> =
DECLARE VARIABLE var datatype;
[DECLARE VARIABLE var datatype; ...]

<block> =
BEGIN
<compound_statement>
[<compound_statement> ...]
END

<compound_statement> =
{<block> | statement;}

The complete syntax of CREATE PROCEDURE is in the online SQL Reference.

Using SET TERM in ISQL

Because each statement in a procedure body must be terminated by a semicolon, you must define a different symbol to terminate the procedure body itself. In ISQL include a SET TERM statement before CREATE PROCEDURE to specify a terminator other than a semicolon. After the body of the procedure, include another SET TERM to change the terminator back to a semicolon.

The following example illustrates the use of SET TERM for a procedure. The terminator is temporarily set to a double exclamation point (!!).

SET TERM !!;

CREATE PROCEDURE SIMPLE

AS BEGIN

. . .

END!!

SET TERM ;!!

There must be a space after SET TERM. Each SET TERM is itself terminated with the current terminator.

Syntax Errors in Stored Procedures

InterBase generates errors during parsing if there is incorrect syntax in a CREATE PROCEDURE statement. Error messages look similar to this:

Statement failed, SQLCODE = -104

Dynamic SQL Error

-SQL error code = -104

-Token unknown - line 4, char 9

-tmp

The line numbers are counted from the beginning of the CREATE PROCEDURE statement, not from the beginning of the data definition file. Characters are counted from the left, and the unknown token indicated is either the source of the error, or immediately to the right of the source of the error. When in doubt, examine the entire line to determine the source of the syntax error.

The Procedure Header

The Procedure Body


The Procedure Header

Everything before AS in the CREATE PROCEDURE statement forms the procedure header. The header contains:

The name of the stored procedure, which must be unique among procedure and table names in the database.

An optional list of input parameters and their data types. The procedure receives the values of the input parameters from the calling program.

Optionally, the RETURNS keyword followed by a list of output parameters and their data types. The procedure returns the values of the output parameters to the calling program.

Declaring Input Parameters

Use input parameters to pass values from an application to a procedure. Any input parameters are given in a comma-delimited list enclosed in parentheses immediately after the procedure name, as follows:

CREATE PROCEDURE name

(var datatype [, var datatype ...])

. . .

Each input parameter declaration has two parts: a name and a data type. The name of the parameter must be unique within the procedure, and the data type can be any standard SQL data type except BLOB and arrays of data types. The name of an input parameter need not match the name of any host parameter in the calling program.

Note:	No more than 1,400 input parameters can be passed to a stored procedure.

Declaring Output Parameters

Use output parameters to return values from a procedure to an application. The RETURNS clause in the procedure header specifies a list of output parameters. The syntax of the RETURNS clause is:

. . .

[RETURNS (var datatype [, var datatype ...])]

AS

. . .

Each output parameter declaration has two parts: a name and a data type. The name of the parameter must be unique within the procedure, and the data type can be any standard SQL data type except BLOB.


The Procedure Body

Everything following the AS keyword in the CREATE PROCEDURE statement forms the procedure body. The body consists of an optional list of local variable declarations followed by a block of statements.

A block is composed of statements in the InterBase procedure and trigger language, bracketed by BEGIN and END. A block can itself include other blocks, so that there may be many levels of nesting.

InterBase procedure and trigger language includes all standard InterBase SQL statements except data definition and transaction statements, plus statements unique to procedure and trigger language.

Features of InterBase procedure and trigger language include:

Assignment statements, to set values of local variables and input/output parameters.

SELECT statements, to retrieve column values. SELECT statements must have an INTO clause as the last clause.

Control-flow statements, such as FOR SELECT . . . DO, IF . . . THEN, and WHILE . . . DO, to perform conditional or looping tasks.

EXECUTE PROCEDURE statements, to invoke other procedures. Recursion is allowed.

Event alerters.

Comments to annotate procedure code.

Exception statements, to return error messages to applications, and WHEN statements to handle specific error conditions.

SUSPEND and EXIT statements, that return control--and return values of output parameters--to the calling application.

BEGIN . . . END Statements

Each block of statements in the procedure body starts with a BEGIN statement and ends with an END statement. BEGIN and END are not followed by a semicolon. In ISQL, the final END in the procedure body is followed by the terminator that you specified in the SET TERM statement.


Using Variables

There are three types of variables that can be used in the body of a procedure:

Input parameters, used to pass values from an application to a stored procedure.

Output parameters, used to pass values from a stored procedure back to the calling application.

Local variables, used to hold values used only within a procedure.

Any of these types of variables can be used in the body of a stored procedure where an expression can appear. They can be assigned a literal value, or assigned a value derived from queries or expression evaluations.

Note:	In SQL statements, precede variables with a colon (:) to signify that they are variables rather than column names. In procedure and trigger language extension statements, you need not precede variables with a colon.

Local Variables

Local variables are declared and used within a stored procedure. They have no effect outside the procedure.

Local variables must be declared at the beginning of a procedure body before they can be used. Declare a local variable as follows:

DECLARE VARIABLE var datatype;

where var is the name of the local variable, unique within the procedure, and datatype is the data type, which can be any SQL data type except BLOB or an array. Each local variable requires a separate DECLARE VARIABLE statement, followed by a semicolon (;).

The following header declares the local variable, any_sales:

CREATE PROCEDURE DELETE_EMPLOYEE (EMP_NUM INTEGER)

AS

DECLARE VARIABLE ANY_SALES INTEGER;

BEGIN

. . .

Input Parameters

Input parameters are used to pass values from an application to a procedure. They are declared in a comma-delimited list in parentheses following the procedure name. Once declared, they can be used in the procedure body anywhere an expression can appear.

Input parameters are passed by value from the calling program to a stored procedure. This means that if the procedure changes the value of an input parameter, the change has effect only within the procedure. When control returns to the calling program, the input parameter still has its original value.

The following procedure header declares two input parameters, emp_no and proj_id:

CREATE PROCEDURE ADD_EMP_PROJ (EMP_NO SMALLINT, PROJ_ID CHAR(5))

AS

. . .

Output Parameters

Output parameters are used to return values from a procedure to the calling application. Declare them in a comma-delimited list in parentheses following the RETURNS keyword in the procedure header. Once declared, they can be used in the procedure body anywhere an expression can appear. For example, the following procedure header declares five output parameters, head_dept, department, mngr_name, title, and emp_cnt:

CREATE PROCEDURE ORG_CHART

RETURNS (HEAD_DEPT CHAR(25), DEPARTMENT CHAR(25),

MNGR_NAME CHAR(20), TITLE CHAR(5), EMP_CNT INTEGER)

If you declare output parameters in the procedure header, the procedure must assign them values to return to the calling application. Values can be derived from any valid expression in the procedure.

A procedure returns output parameter values to the calling application with a SUSPEND statement.

In a SELECT statement that retrieves values from a procedure, the column names must match the names and data types of the procedure's output parameters. In an EXECUTE PROCEDURE statement, the output parameters need not match the names of the procedure's output parameters, but the data types must match.


Using Assignment Statements

A procedure can assign values to variables with the syntax:

variable = expression;

where expression is any valid combination of variables, operators, and expressions, and can include user-defined functions (UDFs) and generators.

A colon need not precede the variable name in an assignment statement. For example, the following statement assigns a value of zero to the local variable, any_sales:

any_sales = 0;

Variables should be assigned values of the data type that they are declared to be. Numeric variables should be assigned numeric values, and character variables assigned character values. InterBase provides automatic type conversion. For example, a character variable may be assigned a numeric value, and the numeric value is automatically converted to a string.


Using SELECT Statements

In a stored procedure, use the SELECT statement with an INTO clause to retrieve a single row value from the database and assign it to a host variable. The SELECT statement must return at most one row from the database, like a standard singleton SELECT. The INTO clause is required and must be the last clause in the statement.

For example, the following statement is a standard singleton SELECT statement in an application:

EXEC SQL

SELECT SUM(BUDGET), AVG(BUDGET)

INTO :tot_budget, :avg_budget

FROM DEPARTMENT

WHERE HEAD_DEPT = :head_dept;

To use this SELECT statement in a procedure, move the INTO clause to the end as follows:

SELECT SUM(BUDGET), AVG(BUDGET)

FROM DEPARTMENT

WHERE HEAD_DEPT = :head_dept

INTO :tot_budget, :avg_budget;


Using FOR SELECT . . . DO Statements

To retrieve multiple rows in a procedure, use the FOR SELECT . . . DO statement. The syntax of FOR SELECT is:

FOR

<select_expr>

DO

<compound_statement>;

FOR SELECT differs from a standard SELECT as follows:

It is a loop statement that retrieves the row specified in the <select_expr> and performs the statement or block following DO for each row retrieved.

The INTO clause in the <select_expr> is required and must come last. This syntax allows FOR . . . SELECT to use the SQL UNION clause, if needed.

For example, the following statement from a procedure selects department numbers into the local variable, rdno, which is then used as an input parameter to the DEPT_BUDGET procedure:

FOR SELECT DEPT_NO

FROM DEPARTMENT

WHERE HEAD_DEPT = :dno

INTO :rdno

DO

BEGIN

EXECUTE PROCEDURE DEPT_BUDGET :rdno RETURNS :sumb;

tot = tot + sumb;

END

. . . ;


Using WHILE . . . DO Statements

WHILE . . . DO is a looping statement that repeats a statement or block of statements as long as a condition is true. The condition is tested at the start of each loop. WHILE . . . DO uses the following syntax:

WHILE (<condition>) DO

<compound_statement>

<compound_statement> =

{<block> | statement;}

The <compound_statement> is executed as long as <condition> remains TRUE. A <block> is one or more compound statements enclosed by BEGIN and END.

For example, the following procedure uses a WHILE . . . DO loop to compute the sum of all integers from one up to the input parameter, i:

SET TERM !!;

CREATE PROCEDURE SUM_INT (i INTEGER) RETURNS (s INTEGER)

AS

BEGIN

s = 0;

WHILE (i > 0) DO

BEGIN

s = s + i;

i = i - 1;

END

END!!

SET TERM ; !!

If this procedure is called from ISQL with the command:

EXECUTE PROCEDURE SUM_INT 4;

then the results will be:

 S

==========

 10


Using IF . . . THEN . . . ELSE Statements

The IF . . . THEN . . . ELSE statement selects alternative courses of action by testing a specified condition. The syntax of IF . . . THEN . . . ELSE is as follows:

IF (<condition>) THEN

<compound_statement>

[ELSE
<compound_statement>]

<compound_statement> =

{<block> | statement;}

<condition> is an expression that must evaluate to TRUE to execute the statement or block following THEN. The optional ELSE clause specifies an alternative statement or block to be executed if <condition> is FALSE.

The following lines of code illustrate the use of IF . . . THEN, assuming the variables line2, first, and last have been previously declared:

. . .

IF (first IS NOT NULL) THEN

line2 = first || " " || last;

ELSE

line2 = last;

. . .


Using Event Alerters

To use an event alerter in a stored procedure, use the following syntax:

POST_EVENT <event_name>;

The parameter, <event_name>, can be either a quoted literal or string variable.

When the procedure is executed, this statement notifies the event manager, which alerts applications waiting for the named event. For example, the following statement posts an event named "new_order":

POST_EVENT "new_order";

Alternatively, a variable can be used for the event name:

POST_EVENT :event_name;

So, the statement can post different events, depending on the value of the string variable, event_name.


Adding Comments

Stored procedure code should be commented to aid debugging and application development. Comments are especially important in stored procedures since they are global to the database and can be used by many different application developers.

Comments in stored procedure definitions are exactly like comments in standard C code, and use the following syntax:

/* comment_text */

comment_text can be any number of lines of text. A comment can appear on the same line as code. For example:

x = 42; /* Initialize value of x. */


EXECUTE PROCEDURE Statements

A stored procedure can itself execute a stored procedure. Each time a stored procedure calls another procedure, the call is said to be nested because it occurs in the context of a previous and still active call to the first procedure. A stored procedure called by another stored procedure is known as a nested procedure.

If a procedure calls itself, it is recursive. Recursive procedures are useful for tasks that involve repetitive steps. Each invocation of a procedure is referred to as an instance, since each procedure call is a separate entity that performs as if called from an application, reserving memory and stack space as required to perform its tasks.

Note:	Stored procedures can be nested up to 1,000 levels deep. This limitation helps to prevent infinite loops that can occur when a recursive procedure provides no absolute terminating condition. Nested procedure calls can be restricted to fewer than 1,000 levels by memory and stack limitations of the server.

The following example illustrates a recursive procedure, FACTORIAL, which calculates factorials. The procedure calls itself recursively to calculate the factorial of num, the input parameter.

SET TERM !!;

CREATE PROCEDURE FACTORIAL (num INT)
RETURNS (n_factorial DOUBLE PRECISION)

AS

DECLARE VARIABLE num_less_one INT;

BEGIN

IF (num = 1) THEN

BEGIN /**** Base case: 1 factorial is 1 ****/

n_factorial = 1;

SUSPEND;

END

ELSE

BEGIN /**** Recursion: num factorial = num * (num-1) factorial ****/

num_less_one = :num - 1;

EXECUTE PROCEDURE FACTORIAL :num_less_one
RETURNING_VALUES :n_factorial;

n_factorial = :n_factorial * :num;

SUSPEND;

END

END!!

SET TERM ;!!

The following C code demonstrates how a host-language program would call FACTORIAL:

. . .

printf("\nCalculate factorial for what value? ");

scanf("%d", &pnum);

EXEC SQL

EXECUTE PROCEDURE FACTORIAL :pnum RETURNING_VALUES :pfact;

printf("%d factorial is %d.\n", pnum, pfact);

. . .

Recursion nesting restrictions would not allow this procedure to calculate factorials for numbers greater than 1,001. Arithmetic overflow, however, occurs for much smaller numbers.


Using SUSPEND, EXIT, and END

The SUSPEND statement suspends execution of a select procedure, passes control back to the program, and resumes execution from the next statement when the next FETCH is executed. SUSPEND also returns values in the output parameters of a stored procedure.

SUSPEND should not be used in executable procedures, since the statements that follow it will never execute. Use EXIT instead to indicate to the reader explicitly that the statement terminates the procedure.

In a select procedure, the SUSPEND statement returns current values of output parameters to the calling program and continues execution. If an output parameter has not been assigned a value, its value is unpredictable, which can lead to errors. A procedure should ensure that all output parameters are assigned values before a SUSPEND.

In both select and executable procedures, EXIT jumps program control to the final END statement in the procedure.

What happens when a procedure reaches the final END statement depends on the type of procedure:

In a select procedure, the final END statement returns control to the application and sets SQLCODE to 100, which indicates there are no more rows to retrieve.

In an executable procedure, the final END statement returns control and values of output parameters, if any, to the calling application.

The behavior of these statements is summarized in the following table

Procedure Type	SUSPEND	EXIT	END
Select procedure	Suspends execution of procedure until next FETCH.	Returns values.	Jumps to final END. Returns control to application. Sets SQLCODE to 100.
Executable procedure	Jumps to final END.	Not Recommended.	Jumps to final END. Returns values. Returns control to application.
Consider the following procedure:

SET TERM !!;

CREATE PROCEDURE P RETURNS (r INTEGER)

AS

BEGIN

r = 0;

WHILE (r < 5) DO

BEGIN

r = r + 1;

SUSPEND;

IF (r = 3) THEN

EXIT;

END

END;

SET TERM ;!!

If this procedure is used as a select procedure, for example:

SELECT * FROM P;

then it returns values 1, 2, and 3 to the calling application, since the SUSPEND statement returns the current value of r to the calling application. The procedure terminates when it encounters EXIT.

If the procedure is used as an executable procedure, for example:

EXECUTE PROCEDURE P;

then it returns 1, since the SUSPEND statement terminates the procedure and returns the current value of r to the calling application. This is not recommended, but is included here for comparison.

Note:	If a select procedure has executable statements following the last SUSPEND in the procedure, all of those statements are executed, even though no more rows are returned to the calling program. The procedure terminates with the final END statement.

Error Behavior

When a procedure encounters an error--either an SQLCODE error, GDSCODE error, or user-defined exception--all statements since the last SUSPEND are undone.

Since select procedures may have multiple SUSPENDs, possibly inside a loop statement, only the actions since the last SUSPEND are undone. Since executable procedures should not use SUSPEND, when an error occurs the entire executable procedure is undone (if EXIT is used, as recommended).


How to Alter Stored Procedures

To change a stored procedure, use ALTER PROCEDURE. This statement changes the definition of an existing stored procedure without affecting its dependencies. If a procedure has dependencies which prevent you from dropping, changing, and recreating it, use ALTER PROCEDURE.

Changes made with ALTER PROCEDURE are automatically reflected in all applications that use the procedure without recompiling and relinking them. Only the creator of a procedure can alter it.

Caution:	Be careful about changing the type, number, and order of input and output parameters to a procedure, since existing code may assume the procedure has its original format.

When a procedure is altered, the new procedure definition replaces the old one. Therefore, to alter a procedure, follow these steps:

1.	Copy the original data definition file used to create the procedure. Alternatively, use ISQL -extract to extract a procedure from the database to a file.

2.	Edit the file, changing CREATE to ALTER, and changing the procedure definition as desired. Retain whatever is still useful.

Syntax

The syntax for ALTER PROCEDURE is similar to CREATE PROCEDURE as shown in the following syntax:

ALTER PROCEDURE name

[(var datatype [, var datatype ...])]

[RETURNS (var datatype [, var datatype ...])]

AS

<procedure_body>;

The procedure name must be the name of an existing procedure. The arguments of the ALTER PROCEDURE statement are the same as CREATE PROCEDURE.

The complete syntax of ALTER PROCEDURE is in the online SQL Reference.


How to Drop Stored Procedures
How to Drop Procedures

The DROP PROCEDURE statement deletes an existing stored procedure from the database. DROP PROCEDURE can be used interactively with ISQL or in a data definition file.

Note:	Procedures cannot be dropped with embedded SQL.

The following restrictions apply to dropping procedures:

Only the creator of a procedure can drop it.

Procedures used by other procedures, triggers, or views cannot be dropped.

Procedures currently in use cannot be dropped.

If you attempt to drop a procedure and receive an error, make sure you have entered the procedure name correctly.

Tip:	To see a list of database procedures and their dependencies, use the ISQL command, SHOW PROCEDURES.

Syntax

The syntax for dropping a procedure is:

DROP PROCEDURE name;

The procedure name must be the name of an existing procedure. The following statement deletes the ACCOUNTS_BY_CLASS procedure:

DROP PROCEDURE ACCOUNTS_BY_CLASS;


Working With Triggers

Trigger Basics

How to Use Triggers

How to Create Triggers

How to Alter Triggers

How to Drop Triggers

Working With Exceptions

How to Handle Errors


Trigger Basics

A trigger is a self-contained routine associated with a table or view that automatically performs an action when a row in the table or view is inserted, updated, or deleted.

A trigger is never called directly. Instead, when an application or user attempts to INSERT, UPDATE, or DELETE a row in a table, any triggers associated with that table and operation are automatically executed, or fired.

Triggers can make use of exceptions, named messages called for error handling. When an exception is raised by a trigger, it returns an error message, terminates the trigger, and undoes any changes made by the trigger, unless the exception is handled with a WHEN statement in the trigger.

The advantages of using triggers are:

Automatic enforcement of data restrictions, to make sure users enter only valid values into columns.

Reduced application maintenance, since changes to a trigger are automatically reflected in all applications that use the associated table without the need to recompile and relink.

Automatic logging of changes to tables. An application can keep a running log of changes with a trigger that fires whenever a table is modified.

Automatic notification of changes to the database with event alerters in triggers.

There are two ways to create, alter, and drop triggers with ISQL:

Interactively

With an input file containing data definition statements

It is preferable to use data definition files, because it is easier to modify these files and provide a record of the changes made to the database. For simple changes to existing triggers or exceptions, the interactive interface can be convenient.

Using a Data Definition File

To create or alter a trigger through a data definition file, create an ISQL script and process it using Windows ISQL.

Note:	The data definition file must include a statement to create or open a database.

The data definition file may include:

Statements to create, alter, or drop triggers. The file can also include statements to create, alter, or drop procedures and exceptions. Exceptions must be created and committed before they can be referenced in procedures and triggers.

Any other ISQL statements.


How to Use Triggers

Triggers are a powerful feature with a variety of uses. Among the ways that triggers can be used are:

To make correlated updates. For example, to keep a log file of changes to a database or table.

To enforce data restrictions, so that only valid data is entered in tables.

Automatic transformation of data. For example, to automatically convert text input to uppercase.

To notify applications of changes in the database using event alerters.

To perform cascading referential integrity updates.

Triggers are stored as part of a database, like stored procedures and exceptions. Once defined to be ACTIVE, they remain active until deactivated with ALTER TRIGGER or removed from the database with DROP TRIGGER.

A trigger is never explicitly called. Rather, an active trigger automatically fires when the specified action occurs on the specified table.

Caution:	If a trigger performs an action that causes it to fire again--or fires another trigger that performs an action that causes it to fire--an infinite loop results. For this reason, it is important to ensure that a trigger's actions never cause the trigger to fire, even indirectly. For example, an endless loop will occur if a trigger fires on INSERT to a table and then performs an INSERT into the same table.

Triggers and Transactions

Triggers operate within the context of the transaction in the program where they are fired. Triggers are considered part of the calling program's current unit of work.

If triggers are fired in a transaction, and the transaction is rolled back, then any actions performed by the triggers are also rolled back.

Triggers and Security


Triggers and Security

Triggers can be granted privileges on tables, just as users or procedures can be granted privileges. Use the GRANT statement, but instead of using TO username, use TO TRIGGER trigger_name. Triggers' privileges can be revoked similarly using REVOKE. For more information about GRANT and REVOKE, see Planning Security.

When a user performs an action that fires a trigger, the trigger will have privileges to perform its actions if:

The trigger has privileges for the action.

The user has privileges for the action.

So, for example, if a user performs an UPDATE of table A, which fires a trigger, and the trigger performs an INSERT on table B, the INSERT will occur if the user has INSERT privileges on the table or the trigger has insert privileges on the table.

If there are insufficient privileges for a trigger to perform its actions, InterBase will set the appropriate SQLCODE error number. The trigger can handle this error with a WHEN clause. If it does not handle the error, an error message will be returned to the application, and the actions of the trigger and the statement which fired it will be undone.


Triggers As Event Alerters

Triggers can be used to post events when a specific change to the database occurs. For example, the following trigger, POST_NEW_ORDER, posts an event named "new_order" whenever a new record is inserted in the SALES table:

SET TERM !! ;

CREATE TRIGGER POST_NEW_ORDER FOR SALES

AFTER INSERT AS

BEGIN

POST_EVENT "new_order";

END !!

SET TERM ; !!

In general, a trigger can use a variable for the event name:

POST_EVENT :event_name;

The parameter, event_name, is declared as a string variable, the statement could post different events, depending on the value of the string variable, event_name. Then, for example, an application can wait for the event to occur, if the event has been declared with EVENT INIT and then instructed to wait for it with EVENT WAIT:

EXEC SQL
EVENT INIT order_wait empdb ("new_order")

EXEC SQL
EVENT WAIT order_wait;


How to Create Triggers

A trigger is defined with the CREATE TRIGGER statement, which is composed of a header and a body. The trigger header contains:

A trigger name, unique within the database.

A table name, identifying the table with which to associate the trigger.

Statements that determine when the trigger fires.

The trigger body contains:

An optional list of local variables and their data types.

A block of statements in InterBase procedure and trigger language, bracketed by BEGIN and END. These statements are performed when the trigger fires. A block can itself include other blocks, so that there may be many levels of nesting.

Important:	Because each statement in the trigger body must be terminated by a semicolon, you must define a different symbol to terminate the trigger body itself. In ISQL, include a SET TERM statement before CREATE TRIGGER to specify a terminator other than a semicolon. After the body of the trigger, include another SET TERM to change the terminator back to a semicolon.

CREATE TRIGGER Syntax

The syntax of CREATE TRIGGER is:

CREATE TRIGGER name FOR table
[ACTIVE | INACTIVE]
{BEFORE | AFTER} {DELETE | INSERT | UPDATE}
[POSITION number]

AS
<trigger_body>

<trigger_body> =

[<variable_declaration_list>]

<block>

<variable_declaration_list> =

DECLARE VARIABLE variable datatype;

[DECLARE VARIABLE variable datatype; ...]

<block> =

BEGIN

<compound_statement>

[<compound_statement> ...]

END

<compound_statement> =

{<block> | statement;}

The complete syntax of CREATE TRIGGER is in the online SQL Reference.

Using SET TERM in ISQL

Because each statement in the trigger body must be terminated by a semicolon, you must define a different symbol to terminate the CREATE TRIGGER statement as a whole. Therefore, include a SET TERM statement before CREATE TRIGGER to specify a terminator other than a semicolon. After CREATE TRIGGER, include another SET TERM to change the terminator back to a semicolon.

There must be a space after SET TERM. Also, each SET TERM is itself terminated with the current terminator.

Syntax Errors in Triggers

InterBase may generate errors during parsing if there is incorrect syntax in the CREATE TRIGGER statement. Error messages look similar to this:

Statement failed, SQLCODE = -104

Dynamic SQL Error

-SQL error code = -104

-Token unknown - line 4, char 9

-tmp

The line numbers are counted from the beginning of the CREATE TRIGGER statement, not from the beginning of the data definition file. Characters are counted from the left, and the unknown token indicated will either be the source of the error or immediately to the right of the source of the error. When in doubt, examine the entire line to determine the source of the syntax error.

The Trigger Header

The Trigger Body


The Trigger Header

Everything before the AS clause in the CREATE TRIGGER statement forms the trigger header. The header must specify the name of the trigger and the name of the associated table or view. The table or view must exist before it can be referenced in CREATE TRIGGER.

The trigger name must be unique among triggers in the database. Using the name of an existing trigger or a system-supplied constraint name results in an error.

The remaining clauses in the trigger header determine when and how the trigger fires:

The trigger status, ACTIVE or INACTIVE, determines whether a trigger is activated when the specified operation occurs. ACTIVE is the default, meaning the trigger fires when the operation occurs. Setting status to INACTIVE with ALTER TRIGGER is useful when developing and testing applications and triggers.

The trigger time indicator, BEFORE or AFTER, determines when the trigger fires relative to the specified operation. BEFORE specifies that trigger actions are performed before the operation. AFTER specifies that trigger actions are performed after the operation.

The trigger statement indicator specifies the SQL operation that causes the trigger to fire: INSERT, UPDATE, or DELETE. Exactly one indicator must be specified. To use the same trigger for more than one operation, duplicate the trigger with another name and specify a different operation.

The optional sequence indicator, POSITION number, specifies the order in which the trigger fires in relation to other triggers on the same table and event. number can be any integer between zero and 32,767. The default is zero. Lower-numbered triggers fire first. Multiple triggers can have the same position number; they will fire in random order.

The following example demonstrates how the POSITION clause determines trigger firing order. Here are four headers of triggers for the ACCOUNTS table:

CREATE TRIGGER A FOR ACCOUNTS BEFORE UPDATE POSITION 5 AS ...

CREATE TRIGGER B FOR ACCOUNTS BEFORE UPDATE POSITION 0 AS ...

CREATE TRIGGER C FOR ACCOUNTS AFTER UPDATE POSITION 5 AS ...

CREATE TRIGGER D FOR ACCOUNTS AFTER UPDATE POSITION 3 AS ...

When this update takes place:

UPDATE ACCOUNTS SET C = "canceled" WHERE C2 = 5;

The following sequence of events happens: trigger B fires, A fires, the update occurs, trigger D fires, then C fires.


The Trigger Body

Everything following the AS keyword in the CREATE TRIGGER statement forms the procedure body. The body consists of an optional list of local variable declarations followed by a block of statements.

A block is composed of statements in the InterBase procedure and trigger language, bracketed by BEGIN and END. A block can itself include other blocks, so that there may be many levels of nesting.

InterBase procedure and trigger language includes all standard InterBase SQL statements except data definition and transaction statements, plus statements unique to procedure and trigger language.

Statements unique to InterBase procedure and trigger language include:

Assignment statements, to set values of local variables.

Control-flow statements, such as IF . . . THEN, WHILE . . . DO, and FOR SELECT . . . DO, to perform conditional or looping tasks.

EXECUTE PROCEDURE statements to invoke stored procedures.

Exception statements, to return error messages, and WHEN statements, to handle specific error conditions.

NEW and OLD context variables, to temporarily hold previous (old) column values and to insert or update (new) values.

Generators, to generate unique numeric values for use in expressions. Generators can be used in procedures and applications as well as triggers, but they are particularly useful in triggers for inserting unique column values.

Note:	All of these statements (except context variables) can be used in both triggers and stored procedures.


NEW and OLD Context Variables

Triggers can use two context variables, OLD, and NEW. The OLD context variable refers to the current or previous values in a row being updated or deleted. OLD is not used for inserts. NEW refers to a new set of INSERT or UPDATE values for a row. NEW is not used for deletes. Context variables are often used to compare the values of a column before and after it is modified.

The syntax for context variables is as follows:

NEW.column

OLD.column

where column is any column in the affected row. Context variables can be used anywhere a regular variable can be used.

New values for a row can only be altered before actions. A trigger that fires after INSERT and tries to assign a value to NEW.column will have no effect. The actual column values are not altered until after the action, so triggers that reference values from their target tables will not see a newly inserted or updated value unless they fire after UPDATE or INSERT.

For example, the following trigger fires after the EMPLOYEE table is updated, and compares an employee's old and new salary. If there is a change in salary, the trigger inserts an entry in the SALARY_HISTORY table.

SET TERM !! ;

CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE

AFTER UPDATE AS

BEGIN

IF (old.salary <> new.salary) THEN

INSERT INTO SALARY_HISTORY

(EMP_NO, CHANGE_DATE, UPDATER_ID, OLD_SALARY, PERCENT_CHANGE)

 VALUES (old.emp_no, "now", USER, old.salary,
(new.salary - old.salary) * 100 / old.salary);

END !!

SET TERM ; !!

Note:	Context variables are never preceded by a colon, even in SQL statements.


Using Generators

A generator is a database object which is automatically incremented each time the special function, GEN_ID( ), is called. GEN_ID( ) can be used in a statement anywhere that a variable can be used. Generators are typically used to ensure that a number inserted into a column is unique, or in sequential order. Generators can be used in procedures and applications as well as triggers, but they are particularly useful in triggers for inserting unique column values.

A generator is created with the CREATE GENERATOR statement and initialized with the SET GENERATOR statement. If not initialized, a generator starts with a value of one.

A generator must be created with CREATE GENERATOR before it can be called by GEN_ID( ). The syntax for using GEN_ID( ) in a statement is:

GEN_ID(genname, step)

genname must be the name of an existing generator, and step is the amount by which the current value of the generator is incremented. step may be an integer or an expression that evaluates to an integer.

The following trigger uses GEN_ID( ) to increment a new customer number before values are inserted into the CUSTOMER table:

SET TERM !! ;

CREATE TRIGGER SET_CUST_NO FOR CUSTOMER

BEFORE INSERT AS

BEGIN

NEW.cust_no = GEN_ID(CUST_NO_GEN, 1);

END !!

SET TERM ; !!

Note:	This trigger must be defined to fire before the insert, since it assigns values to NEW.cust_no.

For a complete discussion of generators and their use, see Working With Generators.


How to Alter Triggers

To update a trigger definition, use ALTER TRIGGER. A trigger can only be altered by its creator.

ALTER TRIGGER can change:

Only trigger header information, including the trigger activation status, when it performs its actions, the event that fires the trigger, and the order in which the trigger fires compared to other triggers.

Only trigger body information, the trigger statements that follow the AS clause.

Both trigger header and trigger body information. In this case, the new trigger definition replaces the old trigger definition.

To alter a trigger defined automatically by a CHECK constraint on a table, use ALTER TABLE to change the table definition.

Syntax

ALTER TRIGGER name

[ACTIVE | INACTIVE]

[{BEFORE | AFTER} {DELETE | INSERT | UPDATE}]

[POSITION number]

AS <trigger_body>;

The syntax of ALTER TRIGGER is the same as CREATE TRIGGER, except:

The CREATE keyword is replaced by ALTER.

FOR table is omitted. ALTER TRIGGER cannot be used to change the table with which the trigger is associated.

The statement need only include parameters that are to be altered in the existing trigger, with certain exceptions.

The complete syntax of ALTER TRIGGER is in the online SQL Reference.


Altering a Trigger Header

When used to change only a trigger header, ALTER TRIGGER requires at least one altered setting after the trigger name. Any setting omitted from ALTER TRIGGER remains unchanged.

The following statement makes the trigger, SAVE_SALARY_CHANGE, inactive:

ALTER TRIGGER SAVE_SALARY_CHANGE INACTIVE;

If the time indicator (BEFORE or AFTER) is altered, then the operation (UPDATE, INSERT, or DELETE) must also be specified. For example, the following statement reactivates the trigger, VERIFY_FUNDS, and specifies that it fire before an UPDATE instead of after:

ALTER TRIGGER SAVE_SALARY_CHANGE

ACTIVE

BEFORE UPDATE;


Altering a Trigger Body

When a trigger body is altered, the new body definition replaces the old definition. When used to change only a trigger body, ALTER TRIGGER need contain any header information other than the trigger's name.

To make changes to a trigger body:

1.	Copy the original data definition file used to create the trigger. Alternatively, use ISQL -extract to extract a trigger from the database to a file.

2.	Edit the file, changing CREATE to ALTER, and delete all trigger header information after the trigger name and before the AS keyword.

3.	Change the trigger definition as desired. Retain whatever is still useful. The trigger body must remain syntactically and semantically complete.

For example, the following ALTER statement modifies the previously introduced trigger, SET_CUST_NO, to insert a row into the (assumed to be previously defined) table, NEW_CUSTOMERS, for each new customer.

SET TERM !! ;

ALTER TRIGGER SET_CUST_NO

BEFORE INSERT AS

BEGIN

new.cust_no = GEN_ID(CUST_NO_GEN, 1);

INSERT INTO NEW_CUSTOMERS(new.cust_no, TODAY)

END !!

SET TERM ; !!


How to Drop Triggers

During database design and application development, a trigger may no longer be useful. To permanently remove a trigger, use DROP TRIGGER.

The following restrictions apply to dropping triggers:

Only the creator of a trigger can drop it.

Triggers currently in use cannot be dropped.

To temporarily remove a trigger, use ALTER TRIGGER and specify INACTIVE in the header.

Syntax

The syntax for dropping a trigger is:

DROP TRIGGER name;

The trigger name must be the name of an existing trigger. The following example drops the trigger, SET_CUST_NO:

DROP TRIGGER SET_CUST_NO;

Note:	You cannot drop a trigger if it is in use by a CHECK constraint (a system-defined trigger). Use ALTER TABLE to remove or modify the CHECK clause that defines the trigger.


Working With Exceptions

An exception is a named error message that can be raised from a trigger or a stored procedure. Exceptions are created with CREATE EXCEPTION, modified with ALTER EXCEPTION, and removed from the database with DROP EXCEPTION. A stored procedure raises an exception with EXCEPTION name.

When raised, an exception returns an error message to the calling program and terminates execution of the procedure or trigger that raised it, unless the exception is handled by a WHEN statement.

Important:	Like procedures and triggers, exceptions are created and stored in a database, where they can be used by any procedure or trigger in the database. Exceptions must be created and committed before they can be raised.

How to Create Exceptions

How to Alter Exceptions

How to Drop Exceptions

How to Raise Exceptions in Stored Procedures

How to Raise Exceptions in Triggers


How to Create Exceptions

To create an exception, use the following CREATE EXCEPTION syntax:

CREATE EXCEPTION name "<message>";

The complete syntax of CREATE EXCEPTION is in the online SQL Reference.

For example, the following statement creates an exception named REASSIGN_SALES:

CREATE EXCEPTION REASSIGN_SALES "Reassign the sales records before deleting this employee.";


How to Alter Exceptions

To change the message returned by an exception, use the following syntax:

ALTER EXCEPTION name "<message>";

The complete syntax of ALTER EXCEPTION is in the online SQL Reference.

Only the creator of an exception can alter it. For example, the following statement changes the text of the exception created in the previous section:

ALTER EXCEPTION REASSIGN_SALES "Can't delete employee--Reassign Sales";

You can alter an exception even though a database object depends on it. If the exception is raised by a trigger, you cannot drop the exception unless you first drop the trigger or stored procedure. Use ALTER EXCEPTION instead.


How to Drop Exceptions

To delete an exception, use the following syntax:

DROP EXCEPTION name;

For example, the following statement drops the exception, REASSIGN_SALES:

DROP EXCEPTION REASSIGN_SALES;

The following restrictions apply to dropping exceptions:

Only the creator of an exception can drop it.

Exceptions used in existing procedures and triggers cannot be dropped.

Exceptions currently in use cannot be dropped.

Tip:	In Windows ISQL, SHOW PROCEDURES displays a list of dependencies, the procedures, exceptions, and tables which the stored procedure uses. SHOW PROCEDURE name displays the body and header information for the named procedure. SHOW TRIGGERS table displays the triggers defined for table. SHOW TRIGGER name displays the body and header information for the named trigger.


How to Raise an Exception in a Stored Procedure

To raise an exception in a stored procedure, use the following syntax:

EXCEPTION name;

where name is the name of an exception that already exists in the database.

When an exception is raised, it does the following:

Terminates the procedure in which it was raised and undoes any actions performed (directly or indirectly) by the procedure.

Returns an error message to the calling application. In ISQL, the error message is displayed on the screen.

Note:	If an exception is handled with a WHEN statement, it behaves differently.

The following statements raise the exception, REASSIGN_SALES:

IF (any_sales > 0) THEN

EXCEPTION REASSIGN_SALES;


How to Raise an Exception in a Trigger

To raise an existing exception in a trigger, use the following syntax:

EXCEPTION name;

Where name is the name of an exception that already exists in the database. Raising an exception:

Terminates the trigger, undoing any changes caused (directly or indirectly) by the trigger.

Returns the exception message to the application which performed the action that fired the trigger. If an ISQL command fired the trigger, the error message is displayed on the screen.

Note:	If an exception is handled with a WHEN statement, it will behave differently.

For example, suppose an exception is created as follows:

CREATE EXCEPTION RAISE_TOO_HIGH "New salary exceeds old by more than 50%. Cannot update record.";

The trigger, SAVE_SALARY_CHANGE, might raise the exception as follows:

SET TERM !! ;

CREATE TRIGGER SAVE_SALARY_CHANGE FOR EMPLOYEE

AFTER UPDATE AS

DECLARE VARIABLE pcnt_raise;

BEGIN

pcnt_raise = (new.salary - old.salary) * 100 / old.salary;

IF (old.salary <> new.salary) THEN

IF (pcnt_raise > 50) THEN

EXCEPTION RAISE_TOO_HIGH;

ELSE

BEGIN

INSERT INTO SALARY_HISTORY (EMP_NO, CHANGE_DATE,
UPDATER_ID, OLD_SALARY, PERCENT_CHANGE)

VALUES (old.emp_no, "now", USER, old.salary,
pcnt_raise);
END !!

SET TERM ; !!


Working With Generators

A generator is a mechanism that creates a unique, sequential number that is automatically inserted into a column by the database when SQL data manipulation operations such as INSERT or UPDATE occur. Generators are typically used to produce unique values that can be inserted into a column that is used as a PRIMARY KEY. For example, a programmer writing an application to log and track invoices may want to ensure that each invoice number entered into the database is unique. The programmer can use a generator to create the invoice numbers automatically, rather than writing specific application code to accomplish this task.

Any number of generators can be defined for a database, as long as each generator has a unique name. A generator is global to the database where it is declared. Any transaction that activates the generator can use or update the current sequence number. InterBase will not assign duplicate generator values across transactions.

How to Create Generators

How to Set or Reset Generator Values

How to Use Generators


How to Create Generators

To create a unique number generator in the database, use the CREATE GENERATOR statement. CREATE GENERATOR declares a generator to the database and sets its starting value to zero (the default). If you want to set the starting value for the generator to a number other than zero, use SET GENERATOR to specify the new value.

The syntax for CREATE GENERATOR is:

CREATE GENERATOR name;

The complete syntax of CREATE GENERATOR is in the online SQL Reference.

The following statement creates the generator, EMPNO_GEN:

CREATE GENERATOR EMPNO_GEN;

Note:	Once defined, a generator cannot be deleted.


How to Set or Reset Generator Values

SET GENERATOR sets a starting value for a newly created generator, or resets the value of an existing generator. The new value for the generator, int, can be an integer from -231 to 231-1. When the GEN_ID( ) function is called, that value is int plus the increment specified in the GEN_ID( ) step parameter.

The syntax for SET GENERATOR is:

SET GENERATOR name TO int;

The complete syntax of SET GENERATOR is in the online SQL Reference.

The following statement sets a generator value to 1,000:

SET GENERATOR CUST_NO_GEN TO 1000;

Caution:	Do not reset a generator unless you are certain that duplicate numbers will not occur. For example, a common use of a generator is to assign a number to a column that is defined with PRIMARY KEY or UNIQUE integrity constraints. Be careful that the new value does not enable duplication of existing column values, or all subsequent insertions and updates will fail with a "Duplicate key" error message.


How to Use Generators

After creating the generator, the data definition statements that make the specific number generator known to the database have been defined; no numbers have been generated yet. To invoke the number generator, you must call the InterBase GEN_ID( ) function. GEN_ID( ) takes two arguments: the name of the generator to call, which must already be defined for the database, and a step value, indicating the amount by which the current value should be incremented (or decremented, if the value is negative). GEN_ID( ) can be called from within a trigger, a stored procedure, or an application whenever an INSERT, UPDATE, or DELETE operation occurs.

The syntax for GEN_ID( ) is:

GEN_ID(genname, step);

The complete syntax of GEN_ID( ) is in the online SQL Reference.

GEN_ID( ) can be called directly from within an application or stored procedure using INSERT, UPDATE, or DELETE statements. For example, the following statement uses GEN_ID( ) to call the generator, g, to increment a purchase order number in the SALES table by one:

INSERT INTO SALES (PO_NUMBER) VALUES (GEN_ID(g,1));

A number is generated by the following sequence of events:

1.	The generator is created and stored in the database.

2.	A trigger, stored procedure, or application references the generator with a call to GEN_ID( ).

3.	A generator returns a value when a trigger fires, or when a stored procedure or application executes. It is up to the trigger, stored procedure, or application to use the value. For example, a trigger can insert the value into a column.

Note:	To stop inserting a generated number in a database column, delete or modify the trigger, stored procedure, or application so that GEN_ID( ) is no longer invoked.


Planning Security

Available SQL Access Privileges

How to Grant Access to Tables

How to Grant Privileges to Execute Stored Procedures

How to Grant Access to Views

How to Revoke User Access

How to Use Views to Restrict Data Access


Available SQL Access Privileges

SQL security is controlled at the table level with access privileges, a list of operations that a user is allowed to perform on a given table or view. The GRANT statement assigns access privileges for a table or view to specified users or procedures. The REVOKE statement removes previously granted access privileges.

GRANT can also enable users or stored procedures to use stored procedures through the EXECUTE privilege, while REVOKE is used to remove those privileges.

Default Table Security and Access

In SQL, all tables are automatically secured against unauthorized access when they are created. Initially, only a table's creator, its owner, has access to a table, and only its owner may use GRANT to assign privileges to other users or to procedures.

Note:	On some platforms InterBase also supports a SYSDBA user who has access to all database objects; furthermore, on platforms that support the concept of a superuser, or user with root or locksmith privileges, such a user also has access to all database objects.

Default Procedure Security and Access

All stored procedures are automatically secured against unauthorized use when they are created. Initially, only a procedure's creator, its owner, can execute or call the procedure, and only its owner may assign EXECUTE privilege to other users or to other procedures.

Note:	On some platforms InterBase also supports a SYSDBA user who has access to all database objects; furthermore, on platforms that support the concept of a superuser, or user with root or locksmith privileges, such a user also has access to all database objects.

Privileges Available

The following table lists the SQL access privileges that may be granted and revoked:

Privilege	Access

ALL	SELECT, DELETE, INSERT, and UPDATE data.

SELECT	Read data.

DELETE	Delete data.

INSERT	Write new data.

UPDATE	Modify existing data.

EXECUTE	Execute or call a stored procedure.

ALL grants or revokes SELECT, DELETE, INSERT, and UPDATE privileges using a single keyword, but does not grant EXECUTE privilege. SELECT, DELETE, INSERT, and UPDATE privileges can also be granted or revoked singly or in combination.

Note:	Statements that grant or revoke EXECUTE privilege cannot grant or revoke other privileges.


How to Grant Access to Tables

To give a user access to a table, use GRANT to assign privileges. At a minimum, GRANT requires parameters which specify:

An access privilege.

The table name to which access is to be granted.

The name of a user to whom the privilege will apply. User names are derived either from the system, or, for remote or secured database connections, from the security database on the server where the database being accessed resides.

The complete syntax of GRANT is in the online SQL Reference.

For example, the following statement grants SELECT privilege for the DEPARTMENTS table to a user, EMIL:

GRANT SELECT ON DEPARTMENTS TO EMIL;

A stored procedure can also be granted privileges for a table. When a procedure is the recipient of privileges, the PROCEDURE keyword must precede the name of the procedure. For example, the following statement grants the INSERT privilege for the ACCOUNTS table to the procedure, MONEY_TRANSFER:

GRANT INSERT ON ACCOUNTS TO PROCEDURE MONEY_TRANSFER;

Tip:	As a security measure, privileges to tables may be granted to a procedure instead of to individual users. If a user has EXECUTE privilege on a procedure that accesses a table, then the user does not need privileges to the table.

You can grant:

Multiple privileges

All privileges

Privileges to a list of users

Privileges to a list of procedures

Privileges to all users

Access to columns in a table

The right to grant privileges


Granting Multiple Privileges

To give a user a specific subset of privileges to a table, but not all of them, list the privileges, separating them with commas, in the GRANT statement. For example, the following statement assigns INSERT and UPDATE privileges for the DEPARTMENTS table to a user, LI:

GRANT INSERT, UPDATE ON DEPARTMENTS TO LI;

Procedures can also be assigned a specific subset of privileges. When a procedure is given privileges, the PROCEDURE keyword must precede its name. For example, the following statement assigns INSERT and UPDATE privileges for the ACCOUNTS table to a procedure, MONEY_TRANSFER:

GRANT INSERT, UPDATE ON ACCOUNTS TO PROCEDURE MONEY_TRANSFER;

Any combination of SELECT, DELETE, INSERT, and UPDATE privileges may be assigned with the GRANT statement.


Granting All Privileges

The ALL privilege combines the SELECT, DELETE, INSERT, and UPDATE privileges for a table in a single expression. It is a shorthand way to assign all SQL access privileges to a user or procedure except for EXECUTE. For example, the following statement grants all access privileges for the DEPARTMENTS table to a user, SUSAN:

GRANT ALL ON DEPARTMENTS TO SUSAN;

SUSAN can now perform SELECT, DELETE, INSERT, and UPDATE operations on the DEPARTMENTS table.

Procedures can be assigned all privileges. When a procedure is assigned privileges, the PROCEDURE keyword must precede its name. For example, the following statement grants all privileges for the ACCOUNTS table to the procedure, MONEY_TRANSFER:

GRANT ALL ON ACCOUNTS TO PROCEDURE MONEY_TRANSFER;


Granting Privileges to a List of Users

GRANT can be used to assign the same access privileges to a number of users at the same time. Instead of indicating a single user to whom privileges should be assigned, provide a list of users, each separated from one another by commas. For example, the following statement gives INSERT and UPDATE privileges for the DEPARTMENTS table to users FRANÇOIS, BEATRICE, and HELGA:

GRANT INSERT, UPDATE ON DEPARTMENTS TO FRANÇOIS, BEATRICE, HELGA;


Granting Privileges to a List of Procedures

GRANT can be used to assign the same access privileges to a number of stored procedures at the same time. Instead of indicating a single procedure to which privileges should be assigned, provide a list of procedures, each separated from one another by commas. The PROCEDURE keyword must precede the first procedure name in the list. For example, the following statement gives INSERT and UPDATE privileges for the ACCOUNTS table to the procedures, ACCT_MAINT, and MONEY_TRANSFER:

GRANT INSERT, UPDATE ON DEPARTMENTS TO PROCEDURE ACCT_MAINT, MONEY_TRANSFER;


Granting Privileges to All Users

To assign the same access privileges for a table to all users, use the PUBLIC keyword rather than listing all users in the GRANT statement. For example, the following statement grants SELECT, INSERT, and UPDATE privileges on the DEPARTMENTS table to all users:

GRANT SELECT, INSERT, UPDATE ON DEPARTMENTS TO PUBLIC;

Important:	PUBLIC only grants privileges to users, not to stored procedures. Privileges granted to users with PUBLIC can only be revoked from PUBLIC.


Granting Users Access to Columns in a Table

In addition to assigning access rights for an entire table, GRANT can assign access rights for columns within a table. To assign access to columns within a table, a list of columns in parentheses, separated from one another with commas, should follow the list of rights to assign in the GRANT statement. For example, the following statement assigns UPDATE access to all users for the CONTACT and PHONE columns in the CUSTOMERS table:

GRANT UPDATE (CONTACT, PHONE) ON CUSTOMERS TO PUBLIC;

You can add to the rights already assigned to users at the table level, but you cannot subtract from them. To restrict user access to a table, use the REVOKE statement.


Granting Users the Right to Grant Privileges

GRANT can also be used to assign grant authority, the right to assign access privileges for a table to other users, but not to stored procedures.

Initially, only a table's owner has grant authority for that table, so only the owner can grant SELECT, DELETE, INSERT, and UPDATE access to other users. When other users are granted access to the table, they cannot, in turn, grant access to still other users unless they have been given permission to do so.

To assign grant authority to another user, include the WITH GRANT OPTION clause at the end of a GRANT statement. For example, the following statement assigns SELECT access to user EMIL, and allows EMIL to grant SELECT access to other users:

GRANT SELECT ON DEPARTMENTS TO EMIL WITH GRANT OPTION;

WITH GRANT OPTION clauses are cumulative, even if issued by different users. For example, EMIL can be given grant authority for SELECT by one user, and grant authority for INSERT by another user.

Grant Authority Restrictions

Users with grant authority can only assign the privileges assigned to them with the WITH GRANT OPTION clause.

For example, in the previous GRANT statement, EMIL is granted SELECT access to the DEPARTMENTS table. EMIL can grant SELECT privilege to other users. Suppose EMIL is now given INSERT access as well, but without the WITH GRANT OPTION:

GRANT INSERT ON DEPARTMENTS TO EMIL;

EMIL can SELECT from and INSERT to the DEPARTMENTS table. EMIL can still grant SELECT privileges to other users, but cannot assign INSERT privileges.

To change a user's existing privileges to include grant authority, issue a second GRANT statement which includes the WITH GRANT OPTION clause. For example to grant EMIL INSERT privilege with grant authority, reissue the GRANT statement and include the WITH GRANT OPTION clause:

GRANT INSERT ON DEPARTMENTS TO EMIL WITH GRANT OPTION;

Grant Authority Implications

Consider every extension of grant authority with care. Once other users are permitted grant authority on a table, they can grant those same privileges, as well as grant authority for them, to other users.

As the number of users with privileges and grant authority for a table increases, the likelihood that different users may grant the same privileges and grant authority to any single user also increases.

SQL permits duplicate privilege and authority assignment under the assumption that it is intentional. Duplicate privilege and authority assignments to a single user have implications for subsequent revocation of that user's privileges and authority.

For example, suppose two users to whom the appropriate privileges and grant authority have been extended, GALENA and SUDHANSHU, both issue the following statement:

GRANT INSERT ON DEPARTMENTS TO SPINOZA WITH GRANT OPTION;

Later, GALENA revokes the privilege and grant authority for SPINOZA:

REVOKE INSERT ON DEPARTMENTS FROM SPINOZA;

GALENA now believes that SPINOZA no longer has INSERT privilege and grant authority for the DEPARTMENTS table. The immediate net effect of the statement is negligible because SPINOZA retains the INSERT privilege and grant authority assigned by SUDHANSHU.

When full control of access privileges on a table is desired, grant authority should not be assigned indiscriminately. In cases where privileges must be universally revoked for a user who may have received rights from several users, there are two options:

Each user who assigned rights must issue an appropriate REVOKE statement.

The table's owner must issue a REVOKE statement for all users of the table, then issue GRANT statements to reestablish access privileges for the users who should not lose their rights.


How to Grant Privileges to Execute Stored Procedures

To use a stored procedure, users or other stored procedures must have EXECUTE privilege for it, using the following GRANT syntax:

GRANT EXECUTE ON PROCEDURE name TO <userlist>;

<userlist> = username [, username ...]
| PROCEDURE name [, name ...] | PUBLIC

A <userlist> can contain both a list of user names and a list of procedure names. If PUBLIC is used, separate lists of users and procedures are prohibited. PUBLIC cannot be used to assign privileges to procedures.

In the following statement, EXECUTE privilege for the FUND_BALANCE procedure is extended to two users, NKOMO, and SUSAN, and to two procedures, ACCT_MAINT, and MONEY_TRANSFER:

GRANT EXECUTE ON PROCEDURE FUND_BALANCE TO NKOMO, SUSAN, PROCEDURE
ACCT_MAINT, MONEY_TRANSFER;


How to Grant Access to Views
Granting Access to Views

In most respects, SQL treats a view as it does any other table. GRANT can be used to assign access privileges for it.

For SELECT privileges, this poses no problem. Reading data from a view does not change the view.

INSERT, UPDATE, and DELETE privileges for an updatable view, on the other hand, should be assigned with caution. To a user assigned these privileges, it appears that changes the user makes are applied to an actual table. In reality, for a user's changes to occur they must be made to the base table underlying the view.

Tip:	Updatable views for which INSERT and UPDATE privileges are to be granted should always be created using the SQL integrity constraint, WITH CHECK OPTION so that users may only update rows in the base table that can be accessed through the view.

Before granting INSERT, UPDATE, and DELETE privileges for a view, determine that it is updatable.

Views That Are Subsets of a Table

When a view is based on a single table, data changes are made directly to the view's underlying table.

For UPDATE, changes only affect the columns visible through the view. Existing values in other invisible and inaccessible columns are not changed. Views created using the SQL integrity constraint, WITH CHECK OPTION, can be updated only if the UPDATE statement fulfills the constraint's requirements.

For DELETE, the removal of a row affects columns invisible through the view. If SQL integrity constraints or triggers exist for any column in the underlying table, and the deletion of the row violates any of those constraints or trigger conditions, the DELETE statement fails.

For INSERT, the addition of a row affects columns both visible and accessible to the view, and columns which are invisible and inaccessible. Insertion succeeds only when:

Data for insertion into visible columns meets SQL integrity constraint criteria for the column, and also meets any trigger conditions that apply.

All other columns may contain NULL values. SQL integrity constraints or triggers for these columns might not allow NULL values in some or all of these columns.

Views With Joins

When a view definition contains a join of any kind, it is no longer a legally updatable view, and InterBase cannot directly update the underlying tables.

Note:	If extreme care is taken, INSERT, UPDATE, and DELETE operations on views with joins are still possible if appropriate triggers are defined on the view. Even if triggers are defined, integrity constraints in the base tables might still prevent the INSERT, UPDATE, and DELETE statements from succeeding.


How to Revoke User Access

To take away a user's or stored procedure's privileges for a table or view, use the REVOKE statement. At a minimum, REVOKE requires parameters that specify the following:

One access privilege to remove.

The table or view to which the privilege revocation applies.

The name of a user for whom or procedure for which the privilege should be revoked.

The complete syntax of REVOKE is in the online SQL Reference.

For example, the following statement removes the SELECT privilege for the user, SUSAN, on the DEPARTMENTS table:

REVOKE SELECT ON DEPARTMENTS FROM SUSAN;

The following statement removes the UPDATE privilege for the procedure, MONEY_TRANSFER, on the ACCOUNTS table:

REVOKE UPDATE ON ACCOUNTS FROM PROCEDURE MONEY_TRANSER;

REVOKE also removes a user's or procedure's privilege to execute a stored procedure. For example, the following statement removes EXECUTE privilege for user EMIL on the MONEY_TRANSFER procedure:

REVOKE EXECUTE ON PROCEDURE MONEY_TRANSFER FROM EMIL;

The next statement removes EXECUTE privilege for the procedure, ACCT_MAINT, on the MONEY_TRANSFER procedure:

REVOKE EXECUTE ON PROCEDURE MONEY_TRANSER FROM PROCEDURE ACCT_MAINT;

Restrictions

The following restrictions and rules of scope apply to the REVOKE statement:

Privileges may only be revoked by the user who granted them.

Other privileges assigned by other users are not affected.

Revoking a privilege for a user, A, to whom grant authority was given, automatically revokes that privilege for all users to whom it was subsequently assigned by user A.

Privileges granted to PUBLIC can only be revoked for PUBLIC.

You can revoke:

Multiple privileges

All privileges

Privileges to a list of users

Privileges to a list of procedures

Privileges to all users

The right to grant privileges


Revoking Multiple Privileges

To remove some, but not all, of the access privileges assigned to a user or procedure, list the privileges to remove, separating them with commas. For example, the following statement removes the INSERT and UPDATE privileges for the DEPARTMENTS table from a user, LI:

REVOKE INSERT, UPDATE ON DEPARTMENTS FROM LI;

The next statement removes INSERT and DELETE privileges for the ACCOUNTS table from a stored procedure, MONEY_TRANSFER:

REVOKE INSERT, DELETE ON ACCOUNTS FROM PROCEDURE MONEY_TRANSFER;

Any combination of previously assigned SELECT, DELETE, INSERT, and UPDATE privileges can be revoked.


Revoking All Privileges

The ALL privilege combines the SELECT, DELETE, INSERT, and UPDATE privileges for a table in a single expression. It is a shorthand way to remove all SQL table access privileges from a user or procedure. For example, the following statement revokes all access privileges for the DEPARTMENTS table for a user, SUSAN:

REVOKE ALL ON DEPARTMENTS FROM SUSAN;

Even if a user does not have all access privileges for a table, ALL can still be used. Using ALL in this manner is helpful when a current user's access rights are unknown.

Important:	ALL does not revoke EXECUTE privilege.


Revoking Privileges For a List of Users

Use REVOKE to remove the same access privileges for a number of users at the same time. Instead of indicating a single user for whom privileges should be revoked, provide a list of users, each separated from one another by commas. For example, the following statement revokes INSERT and UPDATE privileges for the DEPARTMENTS table for users, FRANÇOIS, BEATRICE, and HELGA:

REVOKE INSERT, UPDATE ON DEPARTMENTS FROM FRANÇOIS, BEATRICE, HELGA;


Revoking Privileges For a List of Procedures

REVOKE can be used to remove the same access privileges for a number of procedures at the same time. Instead of indicating a single procedure for which privileges should be revoked, provide a list of procedures, each separated from one another by commas. The PROCEDURE keyword must precede the first procedure listed. For example, the following statement revokes INSERT and UPDATE privileges for the ACCOUNTS table for the procedures, MONEY_TRANSFER, and ACCT_MAINT:

REVOKE INSERT, UPDATE ON ACCOUNTS FROM PROCEDURE MONEY_TRANSFER,
ACCT_MAINT;


Revoking Privileges For All Users

To revoke privileges granted to all users as PUBLIC, use REVOKE with PUBLIC. For example, the following statement revokes SELECT, INSERT, and UPDATE privileges on the DEPARTMENTS table for all users:

REVOKE SELECT, INSERT, UPDATE ON DEPARTMENTS FROM PUBLIC;

When this statement is executed, only the table's owner retains full access privileges to DEPARTMENTS.

Important:	PUBLIC does not revoke privileges for stored procedures. PUBLIC cannot be used to strip privileges from users who were granted them as individual users.


Revoking Grant Authority

To revoke a user's grant authority for a given privilege, use the following REVOKE syntax:

REVOKE GRANT OPTION FOR privilege [, privilege ...] ON table
FROM user;

For example, the following statement revokes SELECT grant authority on the DEPARTMENTS table from a user, EMIL:

REVOKE GRANT OPTION FOR SELECT ON DEPARTMENTS FROM EMIL;


How to Use Views to Restrict Data Access

In addition to using GRANT and REVOKE to control access to database tables, you can use views to restrict data access. A view is usually created as a subset of columns and rows from one or more underlying tables. Because it is only a subset of its underlying tables, a view already provides a measure of access security.

For example, suppose an EMPLOYEES table contains the columns, LAST_NAME, FIRST_NAME, JOB, SALARY, DEPT, and PHONE. This table contains much information that is useful to all employees. It also contains employee information that should remain confidential to almost everyone: SALARY. Rather than allow all employees access to the EMPLOYEES table, a view can be created which allows access to other columns in the EMPLOYEES table, but which excludes SALARY:

CREATE VIEW EMPDATA AS

SELECT LAST_NAME, FIRST_NAME, DEPARTMENT, JOB, PHONE

FROM EMPLOYEES;

Access to the EMPLOYEES table can now be restricted, while SELECT access to the view, EMPDATA, can be granted to everyone.

Note:	Be careful when creating a view from base tables that contain sensitive information. Depending on the data included in a view, it may be possible for users to recreate or infer the missing data.


Working With Transactions

All SQL data definition and data manipulation statements take place within the context of a transaction, a set of SQL statements that works to carry out a single task. Transaction management statements define the beginning and end of a transaction. They also control its behavior and interaction with other simultaneously running transactions that share access to the same data within and across applications.

How to Start a Transaction

How to End a Transaction


How to Start a Transaction

Use SET TRANSACTION to start a transaction, and optionally specify its behavior.

SET TRANSACTION issued without parameters starts a transaction with the following default behavior:

READ WRITE WAIT ISOLATION LEVEL SNAPSHOT

The following table lists the optional SET TRANSACTION parameters for specifying the behavior of the default transaction:

Parameter	Setting

Access Mode	READ ONLY
READ WRITE

Lock Resolution	WAIT
NO WAIT

Isolation Level	SNAPSHOT
SNAPSHOT TABLE STABILITY
READ COMMITTED

Table Reservation	RESERVING

The following statements are equivalent. They both start a transaction with default behavior.

SET TRANSACTION;

SET TRANSACTION READ WRITE WAIT ISOLATION LEVEL SNAPSHOT;

To start a transaction, but change its characteristics, SET TRANSACTION must be used to specify those characteristics that differ from the default. Characteristics that do not differ from the default can be omitted. For example, the following statement starts a transaction for READ ONLY access, WAIT lock resolution, and ISOLATION LEVEL SNAPSHOT:

SET TRANSACTION READ ONLY;

Syntax

The syntax of SET TRANSACTION is:

SET TRANSACTION

[READ WRITE | READ ONLY]

[WAIT | NO WAIT]

[[ISOLATION LEVEL] {SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION]}]

[RESERVING <reserving_clause>

<reserving_clause> = table [, table ...]
[FOR [SHARED | PROTECTED] {READ | WRITE}] [, <reserving_clause>]

The complete syntax of SET TRANSACTION is in the online SQL Reference.


Access Mode

The access mode parameter specifies the type of access a transaction has for the tables it uses. There are two possible settings:

READ ONLY specifies that a transaction can select data from a table, but cannot insert, update, or delete table data.

READ WRITE specifies that a transaction can select, insert, update, and delete table data. This is the default setting if none is specified.

InterBase assumes that most transactions both read and write data. When starting a transaction for reading and writing, READ WRITE can be omitted from SET TRANSACTION statement. For example, the following statements start a transaction for READ WRITE access:

SET TRANSACTION;

SET TRANSACTION READ WRITE;

It is good programming practice to specify a transaction's access mode, even when it is READ WRITE. It makes an application's source code easier to read and debug because the program's intentions are clearly spelled out.

Start a transaction for READ ONLY access when you only need to read data. READ ONLY must be specified. For example, the following statement starts a transaction for read-only access:

SET TRANSACTION READ ONLY;


Lock Resolution

The lock resolution parameter determines what happens when a transaction encounters a lock conflict. There are two options:

WAIT, the default, causes the transaction to wait until locked resources are released. Once the locks are released, the transaction retries its operation.

NO WAIT immediately returns a lock conflict error without waiting for locks to be released.

Because WAIT is the default lock resolution, it need not be specified in a SET TRANSACTION statement. For example, the following statements are equivalent. They both start a transaction, t1, for READ WRITE access, WAIT lock resolution, and READ COMMITTED isolation level:

SET TRANSACTION READ WRITE READ COMMITTED;

SET TRANSACTION READ WRITE WAIT READ COMMITTED;

To use NO WAIT, the lock resolution parameter must be specified. For example, the following statement starts the named transaction, t1, for READ WRITE access, NO WAIT lock resolution, and SNAPSHOT isolation level:

SET TRANSACTION READ WRITE NO WAIT READ SNAPSHOT;

When lock resolution is specified, it follows the optional access mode, and precedes the optional isolation level parameter.

It is good programming practice to specify a transaction's lock resolution, even when it is WAIT. It makes an application's source code easier to read and debug because the program's intentions are clearly spelled out.


Isolation Level

Examples

The isolation level parameter specifies the control a transaction exercises over table access. It determines the:

View of a database the transaction can see.

Table access allowed to this and other simultaneous transactions.

The following table describes the three isolation levels supported by InterBase:

Isolation Level	Purpose

SNAPSHOT	The default isolation level, provides a stable, committed view of the database at the time the transaction starts. Other simultaneous transactions can UPDATE and INSERT rows, but this transaction cannot see those changes. For updated rows, this transaction sees versions of those rows as they existed at the start of the transaction. If this transaction attempts to update or delete rows changed by another transaction, an update conflict is reported.

SNAPSHOT TABLE STABILITY	Provides a transaction sole insert, update, and delete access to the tables it uses. Other simultaneous transactions may still be able to select rows from those tables.

READ COMMITTED	Enables the transaction to see all committed data in the database, and to update rows updated and committed by other simultaneous transactions without causing lost update problems.

The isolation level for most transactions should be either SNAPSHOT or READ COMMITTED. These levels enable simultaneous transactions to select, insert, update, and delete data in shared databases, and they minimize the chance for lock conflicts. Lock conflicts occur in two situations:

When a transaction attempts to update a row already updated or deleted by another transaction. A row updated by a transaction is effectively locked for update to all other transactions until the controlling transaction commits or rolls back. READ COMMITTED transactions can read and update rows updated by simultaneous transactions after they commit.

When a transaction attempts to insert, update, or delete a row in a table locked by another transaction with an isolation level of SNAPSHOT TABLE STABILITY. SNAPSHOT TABLE STABILITY locks entire tables for write access, although concurrent reads by other SNAPSHOT and READ COMMITTED transactions are permitted.

Using SNAPSHOT TABLE STABILITY guarantees that only a single transaction can make changes to tables, but increases the chance of lock conflicts where there are simultaneous transactions attempting to access the same tables.

Comparing Isolation Levels

Choosing Between SNAPSHOT and READ COMMITTED

Isolation Level Interactions


Comparing Isolation Levels

There are five classic problems all transaction management statements must address:

Lost updates, which can occur if an update is overwritten by a simultaneous transaction unaware of the last updates made by another transaction.

Dirty reads, which can occur if the system allows one transaction to select uncommitted changes made by another transaction.

Non-reproducible reads, which can occur if one transaction is allowed to update or delete rows that are repeatedly selected by another transaction. READ COMMITTED transactions permit non-reproducible reads by design, because they can see committed deletes made by other transactions.

Phantom rows, which can occur if one transaction is allowed to select some, but not all, new rows written by another transaction. READ COMMITTED transactions do not prevent phantom rows.

Update side effects, which can occur when row values are interdependent, and their dependencies are not adequately protected or enforced by locking, triggers, or integrity constraints. These conflicts occur when two or more simultaneous transactions randomly and repeatedly access and update the same data; such transactions are called interleaved transactions.

Except as noted, all three InterBase isolation levels control these problems. The following table summarizes how a transaction with a particular isolation level controls access to its data for other simultaneous transactions:

Problem	SNAPSHOT, READ COMMITTED	SNAPSHOT TABLE STABILITY
Lost updates	Other transactions cannot update rows already updated by this transaction.	Other transactions cannot update tables controlled by this transaction.
Dirty reads	Other SNAPSHOT transactions can only read a previous version of a row updated by this transaction. Other READ COMMITTED transactions can only read a previous version, or committed updates.	Other transactions cannot access tables updated by this transaction.
Non- reproducible reads	SNAPSHOT and SNAPSHOT TABLE STABILITY transactions can only read versions of rows committed when they started. READ COMMITTED transactions must expect that reads cannot be reproduced.	SNAPSHOT and SNAPSHOT TABLE STABILITY transactions can only read versions of rows committed when they started. Other transactions cannot access tables updated by this transaction.
Phantom rows	READ COMMITTED transactions may encounter phantom rows.	Other transactions cannot access tables controlled by this transaction.
Update side effects	Other SNAPSHOT transactions can only read a previous version of a row updated by this transaction. Other READ COMMITTED transactions can only read a previous version, or committed updates. Use triggers and integrity constraints to try to avoid any problems with interleaved transactions.	Other transactions cannot update tables controlled by this transaction. Use triggers and integrity constraints to avoid any problems with interleaved transactions.


Choosing Between SNAPSHOT and READ COMMITTED

The choice between SNAPSHOT and READ COMMITTED isolation levels depends on an application's needs. SNAPSHOT is the default InterBase isolation level. READ COMMITTED duplicates SNAPSHOT behavior, but can read subsequent changes committed by other transactions. In many cases, using READ COMMITTED reduces data contention.

SNAPSHOT transactions receive a stable view of a database as it exists the moment the transactions start. READ COMMITTED transactions can see the latest committed versions of rows. Both types of transactions can use SELECT statements unless they encounter the following conditions:

Table locked by SNAPSHOT TABLE STABILITY transaction for UPDATE.

Uncommitted inserts made by other simultaneous transactions. In this case, a SELECT is allowed, but changes cannot be seen.

READ COMMITTED transactions can read the latest committed version of rows. A SNAPSHOT transaction can read only a prior version of the row as it existed before the update occurred.

SNAPSHOT and READ COMMITTED transactions with READ WRITE access can use INSERT, UPDATE, and DELETE unless they encounter tables locked by SNAPSHOT TABLE STABILITY transactions.

SNAPSHOT transactions cannot update or delete rows previously updated or deleted and then committed by other simultaneous transactions. Attempting to update a row previously updated or deleted by another transaction results in an update conflict error.

A READ COMMITTED READ WRITE transaction can read changes committed by other transactions, and subsequently update those changed rows.

Occasional update conflicts may occur when simultaneous SNAPSHOT and READ COMMITTED transactions attempt to update the same row at the same time. When update conflicts occur, expect the following behavior:

For mass or searched updates, updates where a single UPDATE modifies multiple rows in a table, all updates are undone on conflict. The UPDATE can be retried. For READ COMMITTED transactions, the NO RECORD_VERSION option can be used to narrow the window between reads and updates or deletes.

For cursor or positioned updates, where rows are retrieved and updated from an active set one row at a time, only a single update is undone. To retry the update, the cursor must be closed, then reopened, and updates resumed at the point of previous conflict.


Isolation Level Examples

Starting a Transaction With SNAPSHOT Isolation Level

InterBase assumes that the default isolation level for transactions is SNAPSHOT. Therefore, SNAPSHOT need not be specified in SET TRANSACTION to set the isolation level. For example, the following statements are equivalent. They both start a transaction for READ WRITE access and set isolation level to SNAPSHOT.

SET TRANSACTION;

SET TRANSACTION READ WRITE SNAPSHOT;

When an isolation level is specified, it must follow the access and lock resolution modes.

It is good programming practice to specify a transaction's isolation level, even when it is SNAPSHOT. It makes an application's source code easier to read and debug because the program's intentions are clearly spelled out.

Starting a Transaction With READ COMMITTED Isolation Level

To start a READ COMMITTED transaction, the isolation level must be specified. For example, the following statement starts a transaction for READ WRITE access and sets isolation level to READ COMMITTED:

SET TRANSACTION READ WRITE READ COMMITTED;

Isolation level always follows access mode. If the access mode is omitted, isolation level is the first parameter.

READ COMMITTED supports mutually exclusive optional parameters, RECORD_VERSION and NO RECORD_VERSION. They determine READ COMMITTED behavior when it encounters a row where the latest version of that row is uncommitted:

RECORD_VERSION, specifies that the transaction immediately read the latest committed version of a row, even if a more recent uncommitted version also resides on disk.

NO RECORD_VERSION, the default, specifies that the transaction can only read the latest version of a row. If the WAIT lock resolution option is also specified, then the transaction waits until the latest version of a row is committed or rolled back, and retries its read.

Because NO RECORD_VERSION is the default behavior, it need not be specified with READ COMMITTED. For example, the following statements are equivalent. They start a transaction for READ WRITE access and set isolation level to READ COMMITTED NO RECORD_VERSION.

SET TRANSACTION READ WRITE READ COMMITTED;

SET TRANSACTION READ WRITE READ COMMITTED
NO RECORD_VERSION;

RECORD_VERSION must always be specified when it is used. For example, the following statement starts a named transaction, t1, for READ WRITE access and sets isolation level to READ COMMITTED RECORD_VERSION:

SET TRANSACTION READ WRITE READ COMMITTED
RECORD_VERSION;

Starting a Transaction With SNAPSHOT TABLE STABILITY Isolation Level

To start a SNAPSHOT TABLE STABILITY transaction, the isolation level must be specified. For example, the following statement starts a transaction for READ WRITE access and sets isolation level to SNAPSHOT TABLE STABILITY:

SET TRANSACTION READ WRITE SNAPSHOT TABLE STABILITY;

Isolation level always follows the optional access mode and lock resolution parameters, if they are present.

Use SNAPSHOT TABLE STABILITY with care. In an environment where multiple transactions share database access, SNAPSHOT TABLE STABILITY greatly increases the likelihood of lock conflicts.


Isolation Level Interactions

To determine the possibility for lock conflicts between two transactions accessing the same database, each transaction's isolation level and access mode must be considered.

SNAPSHOT and READ COMMITTED transactions offer the least chance for conflicts. For example, if t1 is a SNAPSHOT transaction with READ WRITE access, and t2 is a READ COMMITTED transaction with READ WRITE access, t1 and t2 only conflict when they attempt to update the same rows. If t1 and t2 have READ ONLY access, they never conflict with any other transaction.

A SNAPSHOT TABLE STABILITY transaction with READ WRITE access is guaranteed that it alone can update tables, but it conflicts with all other simultaneous transactions except for SNAPSHOT and READ COMMITTED transactions running in READ ONLY mode. A SNAPSHOT TABLE STABILITY transaction with READ ONLY access is compatible with any other read-only transaction, but conflicts with any transaction that attempts to insert, update, or delete data.


Table Reservation

The optional RESERVING clause enables transactions to guarantee themselves specific levels of access to a subset of available tables at the expense of other simultaneous transactions. Reservation takes place at the start of the transaction instead of only when data manipulation statements require a particular level of access. RESERVING is only useful in an environment where simultaneous transactions share database access. It has three main purposes:

To prevent possible deadlocks and update conflicts that can occur if locks are taken only when actually needed (the default behavior).

To provide for dependency locking, the locking of tables that may be affected by triggers and integrity constraints. While explicit dependency locking is not required, it can assure that update conflicts do not occur because of indirect table conflicts.

To change the level of shared access for one or more individual tables in a transaction. For example, a READ WRITE SNAPSHOT transaction may need exclusive update rights for a single table, and could use the RESERVING clause to guarantee itself sole write access to the table.

To reserve tables for a transaction, use the following SET TRANSACTION syntax:

SET TRANSACTION

[READ WRITE | READ ONLY]

[WAIT | NO WAIT]

[[ISOLATION LEVEL] {SNAPSHOT [TABLE STABILITY]
| READ COMMITTED [[NO] RECORD_VERSION]}]

RESERVING <reserving_clause>;

<reserving_clause> = table [, table ...]
[FOR [SHARED | PROTECTED] {READ | WRITE}] [, <reserving_clause>]

Each table should only appear once in the RESERVING clause. Each table, or a list of tables separated by commas, must be followed by a clause describing the type of reservation requested. The following table lists these reservation options:

Reservation Option	Purpose

PROTECTED READ	Prevents other transactions from updating rows. All transactions can select from the table.

PROTECTED WRITE	Prevents other transactions from updating rows. SNAPSHOT and READ COMMITTED transactions can select from the table, but only this transaction can update rows.

SHARED READ	Any transaction can select from this table. Any READ WRITE transaction can update this table. This is the most liberal reservation mode.

SHARED WRITE	Any SNAPSHOT or READ COMMITTED READ WRITE transaction can update this table. Other SNAPSHOT and READ COMMITTED transactions can also select from this table.

The following statement starts a SNAPSHOT transaction for READ WRITE access, and reserves a single table for PROTECTED WRITE access:

SET TRANSACTION READ WRITE WAIT SNAPSHOT
RESERVING EMPLOYEE FOR PROTECTED WRITE;

The next statement starts a READ COMMITTED transaction for READ WRITE access, and reserves two tables, one for SHARED WRITE, and another for PROTECTED READ:

SET TRANSACTION READ WRITE WAIT READ COMMITTED
RESERVING EMPLOYEES FOR SHARED WRITE, EMP_PROJ
FOR PROTECTED READ;

SNAPSHOT and READ COMMITTED transactions use RESERVING to implement more restrictive access to tables for other simultaneous transactions. SNAPSHOT TABLE STABILITY transactions use RESERVING to reduce the likelihood of deadlock in critical situations.


How to End a Transaction

When a transaction's tasks are complete, or an error prevents a transaction from completing, the transaction must be ended to set the database to a consistent state. There are two statements that end transactions:

COMMIT makes a transaction's changes permanent in the database. It signals that a transaction completed all its actions successfully.

ROLLBACK undoes a transaction's changes, returning the database to its previous state, before the transaction started. ROLLBACK is typically used when one or more errors occur that prevent a transaction from completing successfully.

Both COMMIT and ROLLBACK close the record streams associated with the transaction, reinitialize the transaction name to zero, and release system resources allocated for the transaction. Freed system resources are available for subsequent use by any application or program.

COMMIT and ROLLBACK have additional benefits. They clearly indicate program logic and intention, make a program easier to understand, and most importantly, assure that a transaction's changes are handled as intended by the programmer.

ROLLBACK is frequently used inside error-handling routines to clean up transactions when errors occur. It can also be used to roll back a partially completed transaction prior to retrying it, and it can be used to restore a database to its prior state if a program encounters an unrecoverable error.

If the program ends before a transaction ends, a transaction is automatically rolled back, but databases are not closed. If a program ends without closing the database, data loss or corruption is possible. Therefore, open databases should always be closed by issuing explicit DISCONNECT, COMMIT RELEASE, or ROLLBACK RELEASE statements.


Using COMMIT

Use COMMIT to write transaction changes permanently to a database. COMMIT closes the record streams associated with the transaction, resets the transaction name to zero, and frees system resources assigned to the transaction for other uses. The syntax for COMMIT is:

COMMIT [RETAIN [SNAPSHOT]

The complete syntax of COMMIT is in the online SQL Reference.

For example, the following C code fragment contains a complete transaction. It gives all employees who have worked since December 31, 1992, a 4.3% cost-of-living salary increase. If all qualified employee records are successfully updated, the transaction is committed, and the changes are actually applied to the database.

. . .

SET TRANSACTION SNAPSHOT TABLE STABILITY;

UPDATE EMPLOYEE

SET SALARY = SALARY * 1.043

WHERE HIRE_DATE < "1-JAN-1993";

COMMIT;

. . .

Even READ ONLY transactions that do not change a database should be ended with a COMMIT rather than ROLLBACK. The database is not changed, but the overhead required to start subsequent transactions is greatly reduced.

Committing Updates Without Freeing a Transaction

To write transaction changes to the database without establishing a new transaction context--the system resources, and current state of cursors used in a transaction--use the RETAIN option with COMMIT. In a busy, multi-user environment, maintaining the transaction context for each user speeds up processing and uses fewer system resources than closing and starting a new transaction for each action. The syntax for the RETAIN option is:

COMMIT RETAIN [SNAPSHOT];

COMMIT RETAIN writes all pending changes to the database, ends the current transaction without closing its record stream and cursors and without freeing its system resources, then starts a new transaction and assigns the existing record streams and system resources to the new transaction.

A ROLLBACK executed after a COMMIT RETAIN can only roll back updates and writes occurring after the COMMIT RETAIN.


Using ROLLBACK

Use ROLLBACK to restore the database to its condition prior to the start of the transaction. ROLLBACK also closes the record streams associated with the transaction, resets the transaction name to zero, and frees system resources assigned to the transaction for other uses. The syntax for ROLLBACK is:

ROLLBACK;

The complete syntax of ROLLBACK is in the online SQL Reference.


Handling Errors
How to Handle Errors

Examples

Procedures can handle three kinds of errors with a WHEN . . . DO statement:

Exceptions raised by EXCEPTION statements in the current procedure, in a nested procedure, or in a trigger fired as a result of actions by such a procedure.

SQL errors reported in SQLCODE.

InterBase errors reported in GDSCODE.

The WHEN ANY statement handles any of the three types of errors.

The syntax of the WHEN . . . DO statement is:

WHEN {<error> [, <error> ...] | ANY}

DO <compound_statement>

<error> =

{EXCEPTION exception_name | SQLCODE number | GDSCODE errcode}

Important:	If used, WHEN must be the last statement in a BEGIN . . . END block. It should come after SUSPEND, if present.

Error Handling in Triggers

Errors and exceptions that occur in triggers may be handled using the WHEN statement. If an exception is handled with WHEN, the exception does not return a message to the application and does not necessarily terminate the trigger.

Error handling in triggers works the same as for stored procedures: the actions performed in the blocks up to the error-handling (WHEN) statement are undone and the statements specified by the WHEN statement are performed.


Handling Exceptions

Instead of terminating when an exception occurs, a procedure can respond to and perhaps correct the error condition by handling the exception. When an exception is raised, it does the following:

Seeks a WHEN statement that handles the exception. If one is not found, it terminates execution of the BEGIN . . . END block containing the exception and undoes any actions performed in the block.

Backs out one level to the surrounding BEGIN . . . END block and seeks a WHEN statement that handles the exception, and continues backing out levels until one is found. If no WHEN statement is found, the procedure is terminated and all its actions are undone.

Performs the ensuing statement or block of statements specified by the WHEN statement that handles the exception.

Returns program control to the block in the procedure following the WHEN statement.

Note:	An exception that is handled does not return an error message.


Handling SQL Errors

Procedures can also handle error numbers returned in SQLCODE. After each SQL statement executes, SQLCODE contains a status code indicating the success or failure of the statement. SQLCODE can also contain a warning status, such as when there are no more rows to retrieve in a FOR SELECT loop.

For example, if a procedure attempts to insert a duplicate value into a column defined as a PRIMARY KEY, InterBase returns SQLCODE -803. This error can be handled in a procedure with the following statement:

WHEN SQLCODE -803

DO

BEGIN

. . .

The following procedure includes a WHEN statement to handle SQLCODE -803 (attempt to insert a duplicate value in a UNIQUE key column). If the first column in TABLE1 is a UNIQUE key, and the value of parameter a is the same as one already in the table, then SQLCODE -803 is generated, and the WHEN statement sets an error message returned by the procedure.

SET TERM !!;

CREATE PROCEDURE NUMBERPROC (a INTEGER, b INTEGER)
RETURNS (e CHAR(60)) AS

BEGIN

BEGIN

INSERT INTO TABLE1 VALUES (:a, :b);

WHEN SQLCODE -803 DO

e = "Error Attempting to Insert in TABLE1 - Duplicate Value.";

END;

END!!
SET TERM; !!


Handling InterBase Errors

Procedures can also handle InterBase errors. For example, suppose a statement in a procedure attempts to update a row already updated by another transaction, but not yet committed. In this case, the procedure might receive an InterBase error isc_lock_conflict. If the procedure retries its update, the other transaction may have rolled back its changes and released its locks. By using a WHEN GDSCODE statement, the procedure can handle lock conflict errors and retry its operation.

To handle InterBase error codes, use the following syntax:

WHEN GDSCODE errcode DO <compound_statement>;


Examples of Error Behavior and Handling

When a procedure encounters an error--either an SQLCODE error, GDSCODE error, or user-defined exception--the statements since the last SUSPEND are undone.

SUSPEND should not be used in executable procedures. EXIT should be used to terminate the procedure. If this recommendation is followed, then when an executable procedure encounters an error, the entire procedure is undone. Since select procedures can have multiple SUSPENDs, possibly inside a loop statement, only the actions since the last SUSPEND are undone.

For example, here is a simple executable procedure that attempts to insert the same values twice into the PROJECT table.

SET TERM !! ;

CREATE PROCEDURE NEW_PROJECT

(id CHAR(5), name VARCHAR(20), product VARCHAR(12))

RETURNS (result VARCHAR(80))

AS

BEGIN

INSERT INTO PROJECT (PROJ_ID, PROJ_NAME, PRODUCT)

VALUES (:id, :name, :product);

result = "Values inserted OK.";

INSERT INTO PROJECT (PROJ_ID, PROJ_NAME, PRODUCT)

VALUES (:id, :name, :product);

result = "Values Inserted Again.";

EXIT;

WHEN SQLCODE -803 DO

BEGIN

result = "Could Not Insert Into Table - Duplicate Value";

EXIT;

END

END!!

SET TERM ; !!

This procedure can be invoked with a statement such as:

EXECUTE PROCEDURE NEW_PROJECT "XXX", "Project X", "N/A";

The second INSERT generates an error (SQLCODE -803, "invalid insert--no two rows can have duplicate values."). The procedure returns the string, "Could Not Insert Into Table - Duplicate Value," as specified in the WHEN clause, and the entire procedure is undone.

The next example is written as a select procedure, and invoked with the SELECT statement that follows it:

. . .
INSERT INTO PROJECT (PROJ_ID, PROJ_NAME, PRODUCT)

VALUES (:id, :name, :product);

result = "Values inserted OK.";

SUSPEND;

INSERT INTO PROJECT (PROJ_ID, PROJ_NAME, PRODUCT)

VALUES (:id, :name, :product);

result = "Values Inserted Again.";

SUSPEND;

WHEN SQLCODE -803 DO

BEGIN

result = "Could Not Insert Into Table - Duplicate Value";

EXIT;

END

END!!

SET TERM ; !!

SELECT * FROM SIMPLE("XXX", "Project X", "N/A");

The first INSERT is performed, and SUSPEND returns the result string, "Values Inserted OK." The second INSERT generates the error because there have been no statements performed since the last SUSPEND, and no statements are undone. The WHEN statement returns the string, "Could Not Insert Into Table - Duplicate Value", in addition to the previous result string.

The select procedure successfully performs the insert, while the executable procedure does not.

The next example is a more complex stored procedure that demonstrates SQLCODE error handling and exception handling. It is based on the previous example of a select procedure, and does the following:

Accepts a project ID, name, and product type, and ensures that the ID is in all capitals, and the product type is acceptable.

Inserts the new project data into the PROJECT table, and returns a string confirming the operation, or an error message saying the project is a duplicate.

Uses a FOR . . . SELECT loop with a correlated subquery to get the first three employees not assigned to any project and assign them to the new project using the ADD_EMP_PROJ procedure.

If the CEO's employee number is selected, raises the exception, CEO, which is handled with a WHEN statement that assigns the CEO's administrative assistant (employee number 28) instead to the new project.

Note that the exception, CEO, is handled within the FOR . . . SELECT loop, so that only the block containing the exception is undone, and the loop and procedure continue after the exception is raised.

CREATE EXCEPTION CEO "Can't Assign CEO to Project.";

SET TERM !! ;

CREATE PROCEDURE NEW_PROJECT

(id CHAR(5), name VARCHAR(20), product VARCHAR(12))

RETURNS (result VARCHAR(30), num smallint)

AS

DECLARE VARIABLE emp_wo_proj smallint;

DECLARE VARIABLE i smallint;

BEGIN

id = UPPER(id); /* Project id must be in uppercase. */

 	INSERT INTO PROJECT (PROJ_ID, PROJ_NAME, PRODUCT)

 	VALUES (:id, :name, :product);

 	result = "New Project Inserted OK.";

 	SUSPEND;

/* Add Employees to the new project */

 	i = 0;

 	result = "Project Got Employee Number:";

 	FOR SELECT EMP_NO FROM EMPLOYEE

 	WHERE EMP_NO NOT IN (SELECT EMP_NO FROM EMPLOYEE_PROJECT)

 	INTO :emp_wo_proj

 	DO

 	BEGIN

 	IF (i < 3) THEN

 	BEGIN

 	IF (emp_wo_proj = 5) THEN

 	EXCEPTION CEO;

 	EXECUTE PROCEDURE ADD_EMP_PROJ :emp_wo_proj, :id;

 	num = emp_wo_proj;

 	SUSPEND;

 	END

 	ELSE

 	EXIT;

 	i = i + 1;

WHEN EXCEPTION CEO DO

 	BEGIN

 	EXECUTE PROCEDURE ADD_EMP_PROJ 28, :id;

 	num = 28;

 	SUSPEND;

 	END

END

/* Error Handling */

WHEN SQLCODE -625 DO

BEGIN

IF ((:product <> "software") OR (:product <> "hardware") OR

(:product <> "other") OR (:product <> "N/A")) THEN

result = "Enter product: software, hardware, other, or N/A";

END

WHEN SQLCODE -803 DO

result = "Could not insert into table - Duplicate Value";

END!!

SET TERM ; !!

This procedure can be called with a statement such as:

SELECT * FROM NEW_PROJECT("XYZ", "Alpha project", "software");

With results (in ISQL) such as:

RESULT 	NUM

=========================== 	======

New Project Inserted OK. 	<null>

Project Got Employee Number: 	28

Project Got Employee Number: 	29

Project Got Employee Number: 	36


Error Codes and Messages

Error Sources

Error Reporting and Handling

Trapping Errors With WHENEVER

Checking SQLCODE Value Directly

InterBase Status Array

SQLCODE Error Codes and Messages

InterBase Status Array Error Codes

Server Manager Error Messages


Error Sources

Run-time errors occur at points of user input or program output. When you run a program or use ISQL, the following types of errors may occur:

Error Type	Description	Action

Database error	Database errors can result from any one of many problems, such as conversion errors, arithmetic exceptions, and validation errors.	If you encounter one of these messages: Check any messages.Check the file name or path name and try again.
Bugcheck or internal error	Bugchecks reflect software problems you should report.	If you encounter a bugcheck, execute a traceback and save the output. Submit output and script along with a copy of the database to Borland International, Inc.


Error Reporting and Handling

For reporting and dealing with errors, InterBase utilizes the SQLCODE variable and InterBase codes returned in the status array.

Every executable SQL statement sets the SQLCODE variable, which can serve as a status indicator. During preprocessing, gpre declares this variable automatically. An application can test for and use the SQLCODE variable in one of three ways:

Use the WHENEVER statement to check the value of SQLCODE and direct the program to branch to error-handling routines coded in the application.

Test for SQLCODE directly.

Combine WHENEVER and direct SQLCODE testing.

For SQL programs that must be portable between InterBase and other database management systems, limit error-handling routines to one of these methods.

The InterBase status array displays information about errors that supplements SQLCODE messages.

InterBase applications can check both the SQLCODE message and the message returned in the status array.


Trapping Errors With WHENEVER

The WHENEVER statement traps SQL errors and warnings. WHENEVER tests SQLCODE return values and branches to appropriate error-handling routines in the application. Error routines can range from:

Simple reporting of errors and transaction rollback, or a prompt to the user to reenter a query or data.

More sophisticated routines that react to many possible error conditions in predictable ways.

WHENEVER helps limit the size of an application, since it can call on a single suite of routines for handling errors and warnings.


Checking SQLCODE Value Directly

Applications can test directly for a particular SQLCODE after each SQL statement. If that SQLCODE occurs, the program can branch to a specific routine.

To handle specific error situations, combine checking for SQLCODE with general WHENEVER statements. These steps outline the procedure, which is described in detail in the Programmer's Guide:

Override the WHENEVER branching by inserting a WHENEVER SQLERROR CONTINUE statement. The program now ignores SQLCODE.

Use an SQLCODE-checking statement to check for a particular SQLCODE and direct the program to an alternative procedure.

To return to WHENEVER branching, insert a new WHENEVER statement.

Where portability is not an issue, additional information may be available in the InterBase status array.


InterBase Status Array

Since each SQLCODE value can result from more than one type of error, the InterBase status array (isc_status) provides additional messages that enable further inquiry into SQLCODE errors.

gpre automatically declares isc_status, an array of twenty 32-bit integers, for all InterBase applications during preprocessing. When an error occurs, the status array is loaded with InterBase error codes, message string addresses, and sometimes other numeric, interpretive, platform-specific error data.

This appendix lists all status array codes in "SQL Error Codes and Messages." To see the codes online, display the ibase.h file. The location of this file is system-specific.

Access to Status Array Messages

InterBase provides library functions to retrieve and print status array codes and messages.

isc_print_sqlerror( )

When SQLCODE < 0, this function prints the returned SQLCODE value, the corresponding SQL error message, and any additional InterBase error messages in the status array to the screen. Use within an error-handling routine.

Syntax

isc_print_sqlerror (short SQLCODE, ISC_STATUS *status_vector);

isc_sql_interprete( )

This function retrieves an SQL error message and stores it in a user-supplied buffer for later printing, manipulation, or display. Allow a buffer length of 256 bytes to hold the message. Use when building error display routines or if you are using a windowing system that does not permit direct screen writes. Do not use this function when SQLCODE > 0.

Syntax

isc_sql_interprete(short SQLCODE, char *buffer, short length);

Action to Take for InterBase Error Codes

After any error occurs, you have the following options: ignore the error, log the error and continue processing, roll back the transaction and try again, or roll back the transaction and quit the application.

For the following errors, it is recommended that you roll back the current transaction and try the operation again:

Status Array Code	Action to Take

isc_convert_error	Conversion error: A conversion between data types failed; correct the input and retry the operation.

isc_deadlock	Deadlock: Transaction conflicted with another transaction. Wait and try again.

isc_integ_fail	Integrity check: Operation failed due to a trigger. Examine the cancel code, fix the error, and try again.

isc_lock_conflict	Lock conflict: Transaction unable to obtain the locks it needed. Wait and try again.

isc_no_dup	Duplicate index entry: Attempt to add a duplicate field. Correct field with duplicate and try again.

isc_not_valid	Validation error: Row did not pass validation test. Correct invalid row and try again.


SQLCODE Error Codes and Messages

SQLCODE Error Messages Summary

SQLCODE Codes and Messages


SQLCODE Error Messages Summary

This table summarizes the types of messages SQLCODE can pass to a program:

SQLCODE	Message	Meaning

<0	SQLERROR	Error. The statement did not complete.

0	SUCCESS	Successful completion.

+1-99	SQLWARNING	System warning or informational message.

+100	NOT FOUND	No qualifying records found. End of file.


SQLCODE Codes and Messages

The following table lists SQLCODEs and associated messages for SQL and DSQL. Some SQLCODE values have more than one text message associated with them. In these cases, InterBase returns the most relevant string message for the error that occurred.

When code messages include the name of a database object or object type, the name is represented by a code in the SQLCODE Text column:

<string>: String value, such as the name of a database object or object type.

<long>: Long integer value, such as the identification number or code of a database object or object type.

<digit>: Integer value, such as the identification number or code of a database object or object type.

The InterBase number in the right-hand column is the actual error number returned in the error status vector. You can use InterBase error-handling functions to report messages based on these numbers instead of SQL code, but doing so results in non-portable SQL programs.

SQLCODE	SQLCODE Text	InterBase Number

101	segment buffer length shorter than expected	335544366L
100	no match for first value expression	335544338L
100	invalid database key	335544354L
100	attempted retrieval of more segments than exist	335544367L
100	attempt to fetch past the last record in a record stream	335544374L
-84	table/procedure has non-SQL security class defined	335544554L
-84	column has non-SQL security class defined	335544555L
-84	procedure <string> does not return any values	335544668L
-103	Data type for constant unknown	335544571L
-104	invalid request BLR at offset <long>	335544343L
-104	BLR syntax error: expected <string> at offset <long>, encountered <long>	335544390L
-104	context already in use (BLR error)	335544425L
-104	context not defined (BLR error)	335544426L
-104	bad parameter number	335544429L
-104		335544440L
-104	invalid slice description language at offset <long>	335544456L
-104	Invalid command	335544570L
-104	Internal error	335544579L
-104	Option specified more than once	335544590L
-104	Unknown transaction option	335544591L
-104	Invalid array reference	335544592L
-104	Token unknown - line <long>, char <long>	335544634L
-104	Unexpected end of command	335544608L
-104	Token unknown	335544612L
-150	attempted update of read-only table	335544360L
-150	cannot update read-only view <string>	335544362L
-150	not updatable	335544446L
-150	Cannot define constraints on views	335544546L
-151	attempted update of read-only column	335544359L
-155	<string> is not a valid base table of the specified view	335544658L
-157	must specify column name for view select expression	335544598L
-158	number of columns does not match select list	335544599L
-162	dbkey not available for multi-table views	335544685L
-170	parameter mismatch for procedure <string>	335544512L
-170	External functions cannot have more than10 parameters	335544619L
-171	function <string> could not be matched	335544439L
-171	column not array or invalid dimensions (expected <long>, encountered <long>)	335544458L
-171	Return mode by value not allowed for this data type	335544618L
-172	function <string> is not defined	335544438L
-204	generator <string> is not defined	335544463L
-204	reference to invalid stream number	335544502L
-204	CHARACTER SET <string> is not defined	335544509L
-204	procedure <string> is not defined	335544511L
-204	status code <string> unknown	335544515L
-204	exception <string> not defined	335544516L
-204	Name of Referential Constraint not defined in constraints table.	335544532L
-204	could not find table/procedure for GRANT	335544551L
-204	Implementation of text subtype <digit> not located.	335544568L
-204	Data type unknown	335544573L
-204	Table unknown	335544580L
-204	Procedure unknown	335544581L
-204	COLLATION <string> is not defined	335544588L
-204	COLLATION <string> is not valid for specified CHARACTER SET	335544589L
-204	Trigger unknown	335544595L
-204	alias <string> conflicts with an alias in the same statement	335544620L
-204	alias <string> conflicts with a procedure in the same statement	335544621L
-204	alias <string> conflicts with a table in the same statement	335544622L
-204	there is no alias or table named <string> at this scope level	335544635L
-204	there is no index <string> for table <string>	335544636L
-204	Invalid use of CHARACTER SET or COLLATE	335544640L
-204	BLOB SUB_TYPE <string> is not defined	335544662L
-205	column <string> is not defined in table <string>	335544396L
-205	could not find column for GRANT	335544552L
-206	Column unknown	335544578L
-206	Column is not a BLOB	335544587L
-206	Subselect illegal in this context	335544596L
-208	invalid ORDER BY clause	335544617L
-219	table <string> is not defined	335544395L
-230	WAL Writer error	335544487L
-231	Log file header of <string> too small	335544488L
-232	Invalid version of log file <string>	335544489L
-233	Log file <string> not latest in the chain but open flag still set	335544490L
-234	Log file <string> not closed properly; database recovery may be required	335544491L
-235	Database name in the log file <string> is different	335544492L
-236	Unexpected end of log file <string> at offset <long>	335544493L
-237	Incomplete log record at offset <long> in log file <string>	335544494L
-238	Log record header too small at offset <long> in log file <string>	335544495L
-239	Log block too small at offset <long> in log file <string>	335544496L
-239	Cache length too small	335544691L
-239	Log size too small	335544693L
-239	Log partition size too small	335544694L
-240	Illegal attempt to attach to an uninitialized WAL segment for <string>	335544497L
-241	Invalid WAL parameter block option <string>	335544498L
-242	Cannot roll over to the next log file <string>	335544499L
-243	database does not use Write-ahead Log	335544500L
-244	WAL subsystem encountered error	335544503L
-245	WAL subsystem corrupted	335544504L
-246	Database <string>: WAL subsystem bug for pid <digit>\	335544513L
-247	Could not expand the WAL segment for database <string>	335544514L
-248	Unable to roll over; please see InterBase log.	335544521L
-249	WAL I/O error. Please see InterBase log.	335544522L
-250	WAL writer - Journal server communication error. Please see InterBase log.	335544523L
-251	WAL buffers cannot be increased. Please see InterBase log.	335544524L
-252	WAL setup error. Please see InterBase log.	335544525L
-253	WAL writer synchronization error for the database <string>	335544526L
-254	Cannot start WAL writer for the database <string>	335544527L
-255	Write-ahead Log without shared cache configuration not allowed	335544556L
-257	WAL defined; Cache Manager must be started first	335544566L
-258	Overflow log specification required for round-robin log	335544567L
-259	Write-ahead Log with shadowing configuration not allowed	335544629L
-260	Cache redefined	335544690L
-260	Log redefined	335544692L
-261	Partitions not supported in series of log file specification	335544695L
-261	Total length of a partitioned log must be specified	335544696L
-281	table <string> is not referenced in plan	335544637L
-282	table <string> is referenced more than once in plan; use aliases to distinguish	335544638L
-282	the table <string> is referenced twice; use aliases to differentiate	335544643L
-282	table <string> is referenced twice in view; use an alias to distinguish	335544659L
-282	view <string> has more than one base table; use aliases to distinguish	335544660L
-283	table <string> is referenced in the plan but not the from list	335544639L
-284	index <string> cannot be used in the specified plan	335544642L
-291	Column used in a PRIMARY/UNIQUE constraint must be NOT NULL.	335544531L
-292	Cannot update constraints (RDB$REF_CONSTRAINTS).	335544534L
-293	Cannot update constraints (RDB$CHECK_CONSTRAINTS).	335544535L
-294	Cannot delete CHECK constraint entry (RDB$CHECK_CONSTRAINTS)	335544536L
-295	Cannot update constraints (RDB$RELATION_CONSTRAINTS).	335544545L
-296	internal isc software consistency check (invalid RDB$CONSTRAINT_TYPE)	335544547L
-297	Operation violates CHECK constraint <string> on view or table	335544558L
-313	count of column list and variable list do not match	335544669L
-314	Cannot transliterate character between character sets	335544565L
-401	invalid comparison operator for find operation	335544647L
-402	attempted invalid operation on a BLOB	335544368L
-402	BLOB and array data types are not supported for <string> operation	335544414L
-402	data operation not supported	335544427L
-406	subscript out of bounds	335544457L
-407	null segment of UNIQUE KEY	335544435L
-413	conversion error from string "<string>"	335544334L
-413	filter not found to convert type <long> to type <long>	335544454L
-501	invalid request handle	335544327L
-501	Attempt to reclose a closed cursor	335544577L
-502	Declared cursor already exists	335544574L
-502	Attempt to reopen an open cursor	335544576L
-504	Cursor unknown	335544572L
-508	no current record for fetch operation	335544348L
-510	Cursor not updatable	335544575L
-518	Request unknown	335544582L
-519	The PREPARE statement identifies a prepare statement with an open cursor	335544688L
-530	violation of FOREIGN KEY constraint: "<string>"	335544466L
-530	Cannot prepare a CREATE DATABASE/SCHEMA statement	335544597L
-532	transaction marked invalid by I/O error	335544469L
-551	no permission for <string> access to <string> <string>	335544352L
-552	only the owner of a table may reassign ownership	335544550L
-552	user does not have GRANT privileges for operation	335544553L
-553	cannot modify an existing user privilege	335544529L
-595	the current position is on a crack	335544645L
-596	illegal operation when at beginning of stream	335544644L
-597	Preceding file did not specify length, so <string> must include starting page number	335544632L
-598	Shadow number must be a positive integer	335544633L
-599	gen.c: node not supported	335544607L
-600	A node name is not permitted in a secondary, shadow, cache or log file name	335544625L
-600	sort error: corruption in data structure	335544680L
-601	database or file exists	335544646L
-604	Array declared with too many dimensions	335544593L
-604	Illegal array dimension range	335544594L
-605	Inappropriate self-reference of column	335544682L
-607	unsuccessful metadata update	335544351L
-607	cannot modify or erase a system trigger	335544549L
-607	Array/BLOB/DATE data types not allowed in arithmetic	335544657L
-615	lock on table <string> conflicts with existing lock	335544475L
-615	requested record lock conflicts with existing lock	335544476L
-615	cannot drop log file when journaling is enabled	335544501L
-615	refresh range number <long> already in use	335544507L
-616	Cannot delete PRIMARY KEY being used in FOREIGN KEY definition.	335544530L
-616	Cannot delete index used by an Integrity Constraint	335544539L
-616	Cannot modify index used by an Integrity Constraint	335544540L
-616	Cannot delete trigger used by a CHECK Constraint	335544541L
-616	Cannot delete column being used in an Integrity Constraint.	335544543L
-616	there are <long> dependencies	335544630L
-616	last column in a table cannot be deleted	335544674L
-617	Cannot update trigger used by a CHECK Constraint	335544542L
-617	Cannot rename column being used in an Integrity Constraint.	335544544L
-618	Cannot delete index segment used by an Integrity Constraint	335544537L
-618	Cannot update index segment used by an Integrity Constraint	335544538L
-625	validation error for column <string>, value "<string>"	335544347L
-637	duplicate specification of <string> - not supported	335544664L
-660	Non-existent PRIMARY or UNIQUE KEY specified for FOREIGN KEY.	335544533L
-660	cannot create index <string>	335544628L
-663	segment count of 0 defined for index <string>	335544624L
-663	too many keys defined for index <string>	335544631L
-663	too few key columns found for index <string> (incorrect column name?)	335544672L
-664	key size exceeds implementation restriction for index "<string>"	335544434L
-677	<string> extension error	335544445L
-685	invalid BLOB type for operation	335544465L
-685	attempt to index BLOB column in index <string>	335544670L
-685	attempt to index array column in index <string>	335544671L
-689	page <long> is of wrong type (expected <long>, found <long>)	335544403L
-689	wrong page type	335544650L
-690	segments not allowed in expression index <string>	335544679L
-691	new record size of <long> bytes is too big	335544681L
-692	maximum indexes per table (<digit>) exceeded	335544477L
-693	Too many concurrent executions of the same request	335544663L
-694	cannot access column <string> in view <string>	335544684L
-802	arithmetic exception, numeric overflow, or string truncation	335544321L
-803	attempt to store duplicate value (visible to active transactions) in unique index "<string>"	335544349L
-803	violation of PRIMARY or UNIQUE KEY constraint: "<string>"	335544665L
-804	wrong number of arguments on call	335544380L
-804	SQLDA missing or incorrect vresion, or incorrect number/type of variables	335544583L
-804	Count of columns not equal count of values	335544584L
-804	Function unknown	335544586L
-806	Only simple column names permitted for VIEW WITH CHECK OPTION	335544600L
-807	No where clause for VIEW WITH CHECK OPTION	335544601L
-808	Only one table allowed for VIEW WITH CHECK OPTION	335544602L
-809	DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION	335544603L
-810	No subqueries permitted for VIEW WITH CHECK OPTION	335544605L
-811	multiple rows in singleton select	335544652L
-816	external file could not be opened for output	335544651L
-817	attempted update during read-only transaction	335544361L
-817	attempted write to read-only BLOB	335544371L
-817	operation not supported	335544444L
-820	metadata is obsolete	335544356L
-820	unsupported on-disk structure for file <string>; found <long>, support <long>	335544379L
-820	wrong DYN version	335544437L
-820	minor version too high found <long> expected <long>	335544467L
-823	invalid bookmark handle	335544473L
-824	invalid lock level <digit>	335544474L
-825	invalid lock handle	335544519L
-826	Invalid statement handle	335544585L
-827	invalid direction for find operation	335544655L
-828	invalid key position	335544678L
-829	invalid column reference	335544616L
-830	column used with aggregate	335544615L
-831	Attempt to define a second PRIMARY KEY for the same table	335544548L
-832	FOREIGN KEY column count does not match PRIMARY KEY	335544604L
-833	expression evaluation not supported	335544606L
-834	refresh range number <long> not found	335544508L
-835	bad checksum	335544649L
-836	exception <digit>	335544517L
-837	restart shared cache manager	335544518L
-838	database <string> shutdown in <digit> seconds	335544560L
-839	journal file wrong format	335544686L
-840	intermediate journal file full	335544687L
-841	too many versions	335544677L
-842	Precision should be greater than 0	335544697L
-842	Scale cannot be greater than precision	335544698L
-842	Short integer expected	335544699L
-842	Long integer expected	335544700L
-842	Unsigned short integer expected	335544701L
-901	invalid database key	335544322L
-901	unrecognized database parameter block	335544326L
-901	invalid BLOB handle	335544328L
-901	invalid BLOB ID	335544329L
-901	invalid parameter in transaction parameter block	335544330L
-901	invalid format for transaction parameter block	335544331L
-901	invalid transaction handle (expecting explicit transaction start)	335544332L
-901	attempt to start more than <long> transactions	335544337L
-901	information type inappropriate for object specified	335544339L
-901	no information of this type available for object specified	335544340L
-901	unknown information item	335544341L
-901	action cancelled by trigger (<long>) to preserve data integrity	335544342L
-901	lock conflict on no wait transaction	335544345L
-901	program attempted to exit without finishing database	335544350L
-901	transaction is not in limbo	335544353L
-901	BLOB was not closed	335544355L
-901	cannot disconnect database with open transactions (<long> active)	335544357L
-901	message length error (encountered <long>, expected <long>)	335544358L
-901	no transaction for request	335544363L
-901	request synchronization error	335544364L
-901	request referenced an unavailable database	335544365L
-901	attempted read of a new, open BLOB	335544369L
-901	attempted action on blob outside transaction	335544370L
-901	attempted reference to BLOB in unavailable database	335544372L
-901	table <string> was omitted from the transaction reserving list	335544376L
-901	request includes a DSRI extension not supported in this implementation	335544377L
-901	feature is not supported	335544378L
-901	<string>	335544382L
-901	unrecoverable conflict with limbo transaction <long>	335544383L
-901	internal error	335544392L
-901	database handle not zero	335544407L
-901	transaction handle not zero	335544408L
-901	transaction in limbo	335544418L
-901	transaction not in limbo	335544419L
-901	transaction outstanding	335544420L
-901	undefined message number	335544428L
-901	blocking signal has been received	335544431L
-901	database system cannot read argument <long>	335544442L
-901	database system cannot write argument <long>	335544443L
-901	<string>	335544450L
-901	transaction <long> is <string>	335544468L
-901	invalid statement handle	335544485L
-901	lock time-out on wait transaction	335544510L
-901	invalid service handle	335544559L
-901	wrong version of service parameter block	335544561L
-901	unrecognized service parameter block	335544562L
-901	service <string> is not defined	335544563L
-901	INDEX <string>	335544609L
-901	EXCEPTION <string>	335544610L
-901	COLUMN <string>	335544611L
-901	union not supported	335544613L
-901	Unsupported DSQL construct	335544614L
-901	Illegal use of keyword VALUE	335544623L
-901	TABLE <string>	335544626L
-901	PROCEDURE <string>	335544627L
-901	Specified domain or source column does not exist	335544641L
-901	variable <string> conflicts with parameter in same procedure	335544656L
-901	server version too old to support all CREATE DATABASE options	335544666L
-901	cannot delete	335544673L
-901	sort error	335544675L
-902	internal isc software consistency check (<string>)	335544333L
-902	database file appears corrupt (<string>)	335544335L
-902	I/O error during "<string>" operation for file "<string>"	335544344L
-902	corrupt system table	335544346L
-902	operating system directive <string> failed	335544373L
-902	internal error	335544384L
-902	internal error	335544385L
-902	internal error	335544387L
-902	block size exceeds implementation restriction	335544388L
-902	incompatible version of on-disk structure	335544394L
-902	internal error	335544397L
-902	internal error	335544398L
-902	internal error	335544399L
-902	internal error	335544400L
-902	internal error	335544401L
-902	internal error	335544402L
-902	database corrupted	335544404L
-902	checksum error on database page <long>	335544405L
-902	index is broken	335544406L
-902	transaction--request mismatch (synchronization error)	335544409L
-902	bad handle count	335544410L
-902	wrong version of transaction parameter block	335544411L
-902	unsupported BLR version (expected <long>, encountered <long>)	335544412L
-902	wrong version of database parameter block	335544413L
-902	database corrupted	335544415L
-902	internal error	335544416L
-902	internal error	335544417L
-902	internal error	335544422L
-902	internal error	335544423L
-902	lock manager error	335544432L
-902	SQL error code = <long>	335544436L
-902		335544448L
-902		335544449L
-902	cache buffer for page <long> invalid	335544470L
-902	there is no index in table <string> with id <digit>	335544471L
-902	Your user name and password are not defined. Ask your database administrator to set up an InterBase login.	335544472L
-902	enable journal for database before starting online dump	335544478L
-902	online dump failure. Retry dump	335544479L
-902	an online dump is already in progress	335544480L
-902	no more disk/tape space. Cannot continue online dump	335544481L
-902	journaling allowed only if database has Write-ahead Log	335544482L
-902	maximum number of online dump files that can be specified is 16	335544483L
-902	error in opening Write-ahead Log file during recovery	335544484L
-902	Write-ahead log subsystem failure	335544486L
-902	must specify archive file when enabling long term journal for databases with round-robin log files	335544505L
-902	database <string> shutdown in progress	335544506L
-902	long-term journaling already enabled	335544520L
-902	database <string> shutdown	335544528L
-902	database shutdown unsuccessful	335544557L
-902	cannot attach to password database	335544653L
-902	cannot start transaction for password database	335544654L
-902	long-term journaling not enabled	335544564L
-902	Dynamic SQL Error	335544569L
-904	invalid database handle (no active connection)	335544324L
-904	unavailable database	335544375L
-904	Implementation limit exceeded	335544381L
-904	too many requests	335544386L
-904	buffer exhausted	335544389L
-904	buffer in use	335544391L
-904	request in use	335544393L
-904	no lock manager available	335544424L
-904	unable to allocate memory from operating system	335544430L
-904	update conflicts with concurrent update	335544451L
-904	object <string> is in use	335544453L
-904	cannot attach active shadow file	335544455L
-904	a file in manual shadow <long> is unavailable	335544460L
-904	cannot add index, index root page is full.	335544661L
-904	sort error: not enough memory	335544676L
-904	request depth exceeded. (Recursive definition?)	335544683L
-906	product <string> is not licensed	335544452L
-909	drop database completed with errors	335544667L
-911	record from transaction <long> is stuck in limbo	335544459L
-913	deadlock	335544336L
-922	file <string> is not a valid database	335544323L
-923	connection rejected by remote interface	335544421L
-923	secondary server attachments cannot validate databases	335544461L
-923	secondary server attachments cannot start journaling	335544462L
-923	secondary server attachments cannot start logging	335544464L
-924	bad parameters on attach or create database	335544325L
-924	communication error with journal "<string>"	335544433L
-924	database detach completed with errors	335544441L
-924	Connection lost to pipe server	335544648L
-926	no rollback performed	335544447L
-999	InterBase error	335544689L


InterBase Status Array Error Codes

This section lists InterBase error codes and associated messages returned in the status array in the following tables. When code messages include the name of a database object or object type, the name is represented by a code in the Message column:

<string>: String value, such as the name of a database object or object type.

<digit>: Integer value, such as the identification number or code of a database object or object type.

<long>: Long integer value, such as the identification number or code of a database object or object type.

The following table lists SQL Status Array codes for embedded SQL programs, DSQL, and ISQL.

Error Code	Number	Message

isc_arith_except	335544321L	arithmetic exception, numeric overflow, or string truncation
isc_bad_dbkey	335544322L	invalid database key
isc_bad_db_format	335544323L	file <string> is not a valid database
isc_bad_db_handle	335544324L	invalid database handle (no active connection)
isc_bad_dpb_content	335544325L	bad parameters on attach or create database
isc_bad_dpb_form	335544326L	unrecognized database parameter block
isc_bad_req_handle	335544327L	invalid request handle
isc_bad_segstr _handle	335544328L	invalid BLOB handle
isc_bad_segstr_id	335544329L	invalid BLOB ID
isc_bad_tpb_content	335544330L	invalid parameter in transaction parameter block
isc_bad_tpb_form	335544331L	invalid format for transaction parameter block
isc_bad_trans_handle	335544332L	invalid transaction handle (expecting explicit transaction start)
isc_bug_check	335544333L	internal isc software consistency check (<string>)
isc_convert_error	335544334L	conversion error from string "<string>"
isc_db_corrupt	335544335L	database file appears corrupt (<string>)
isc_deadlock	335544336L	deadlock
isc_excess_trans	335544337L	attempt to start more than <long> transactions
isc_from_no_match	335544338L	no match for first value expression
isc_infinap	335544339L	information type inappropriate for object specified
isc_infona	335544340L	no information of this type available for object specified
isc_infunk	335544341L	unknown information item
isc_integ_fail	335544342L	action cancelled by trigger (<long>) to preserve data integrity
isc_invalid_blr	335544343L	invalid request BLR at offset <long>
isc_io_error	335544344L	I/O error during "<string>" operation for file "<string>"
isc_lock_conflict	335544345L	lock conflict on no wait transaction
isc_metadata_corrupt	335544346L	corrupt system table
isc_not_valid	335544347L	validation error for column <string>, value "<string>"
isc_no_cur_rec	335544348L	no current record for fetch operation
isc_no_dup	335544349L	attempt to store duplicate value (visible to active transactions) in unique index "<string>"
isc_no_finish	335544350L	program attempted to exit without finishing database
isc_no_meta_update	335544351L	unsuccessful metadata update
isc_no_priv	335544352L	no permission for <string> access to <string> <string>
isc_no_recon	335544353L	transaction is not in limbo
isc_no_record	335544354L	invalid database key
isc_no_segstr_close	335544355L	BLOB was not closed
isc_obsolete _metadata	335544356L	metadata is obsolete
isc_open_trans	335544357L	cannot disconnect database with open transactions (<long> active)
isc_port_len	335544358L	message length error (encountered <long>, expected <long>)
isc_read_only_field	335544359L	attempted update of read-only column
isc_read_only_rel	335544360L	attempted update of read-only table
isc_read_only_trans	335544361L	attempted update during read-only transaction
isc_read_only_view	335544362L	cannot update read-only view <string>
isc_req_no_trans	335544363L	no transaction for request
isc_req_sync	335544364L	request synchronization error
isc_req_wrong_db	335544365L	request referenced an unavailable database
isc_segment	335544366L	segment buffer length shorter than expected
isc_segstr_eof	335544367L	attempted retrieval of more segments than exist
isc_segstr_no_op	335544368L	attempted invalid operation on a BLOB
isc_segstr_no_read	335544369L	attempted read of a new, open BLOB
isc_segstr_no_trans	335544370L	attempted action on blob outside transaction
isc_segstr_no_write	335544371L	attempted write to read-only BLOB
isc_segstr_wrong_db	335544372L	attempted reference to BLOB in unavailable database
isc_sys_request	335544373L	operating system directive <string> failed
isc_stream_eof	335544374L	attempt to fetch past the last record in a record stream
isc_unavailable	335544375L	unavailable database
isc_unres_rel	335544376L	table <string> was omitted from the transaction reserving list
isc_uns_ext	335544377L	request includes a DSRI extension not supported in this implementation
isc_wish_list	335544378L	feature is not supported
isc_wrong_ods	335544379L	unsupported on-disk structure for file <string>; found <long>, support <long>
isc_wronumarg	335544380L	wrong number of arguments on call
isc_imp_exc	335544381L	Implementation limit exceeded
isc_random	335544382L	<string>
isc_fatal_conflict	335544383L	unrecoverable conflict with limbo transaction <long>
isc_badblk	335544384L	internal error
isc_invpoolcl	335544385L	internal error
isc_nopoolids	335544386L	too many requests
isc_relbadblk	335544387L	internal error
isc_blktoobig	335544388L	block size exceeds implementation restriction
isc_bufexh	335544389L	buffer exhausted
isc_syntaxerr	335544390L	BLR syntax error: expected <string> at offset <long>, encountered <long>
isc_bufinuse	335544391L	buffer in use
isc_bdbincon	335544392L	internal error
isc_reqinuse	335544393L	request in use
isc_badodsver	335544394L	incompatible version of on-disk structure
isc_relnotdef	335544395L	table <string> is not defined
isc_fldnotdef	335544396L	column <string> is not defined in table <string>
isc_dirtypage	335544397L	internal error
isc_waifortra	335544398L	internal error
isc_doubleloc	335544399L	internal error
isc_nodnotfnd	335544400L	internal error
isc_dupnodfnd	335544401L	internal error
isc_locnotmar	335544402L	internal error
isc_badpagtyp	335544403L	page <long> is of wrong type (expected <long>, found <long>)
isc_corrupt	335544404L	database corrupted
isc_badpage	335544405L	checksum error on database page <long>
isc_badindex	335544406L	index is broken
isc_dbbnotzer	335544407L	database handle not zero
isc_tranotzer	335544408L	transaction handle not zero
isc_trareqmis	335544409L	transaction--request mismatch (synchronization error)
isc_badhndcnt	335544410L	bad handle count
isc_wrotpbver	335544411L	wrong version of transaction parameter block
isc_wroblrver	335544412L	unsupported BLR version (expected <long>, encountered <long>)
isc_wrodpbver	335544413L	wrong version of database parameter block
isc_blobnotsup	335544414L	BLOB and array data types are not supported for <string> operation
isc_badrelation	335544415L	database corrupted
isc_nodetach	335544416L	internal error
isc_notremote	335544417L	internal error
isc_trainlim	335544418L	transaction in limbo
isc_notinlim	335544419L	transaction not in limbo
isc_traoutsta	335544420L	transaction outstanding
isc_connect_reject	335544421L	connection rejected by remote interface
isc_dbfile	335544422L	internal error
isc_orphan	335544423L	internal error
isc_no_lock_mgr	335544424L	no lock manager available
isc_ctxinuse	335544425L	context already in use (BLR error)
isc_ctxnotdef	335544426L	context not defined (BLR error)
isc_datnotsup	335544427L	data operation not supported
isc_badmsgnum	335544428L	undefined message number
isc_badparnum	335544429L	bad parameter number
isc_virmemexh	335544430L	unable to allocate memory from operating system
isc_blocking_signal	335544431L	blocking signal has been received
isc_lockmanerr	335544432L	lock manager error
isc_journerr	335544433L	communication error with journal "<string>"
isc_keytoobig	335544434L	key size exceeds implementation restriction for index "<string>"
isc_nullsegkey	335544435L	null segment of UNIQUE KEY
isc_sqlerr	335544436L	SQL error code = <long>
isc_wrodynver	335544437L	wrong DYN version
isc_funnotdef	335544438L	function <string> is not defined
isc_funmismat	335544439L	function <string> could not be matched
isc_bad_msg_vec	335544440L
isc_bad_detach	335544441L	database detach completed with errors
isc_noargacc_read	335544442L	database system cannot read argument <long>
isc_noargacc_write	335544443L	database system cannot write argument <long>
isc_read_only	335544444L	operation not supported
isc_ext_err	335544445L	<string> extension error
isc_non_updatable	335544446L	not updatable
isc_no_rollback	335544447L	no rollback performed
isc_bad_sec_info	335544448L
isc_invalid_sec_info	335544449L
isc_misc_interpreted	335544450L	<string>
isc_update_conflict	335544451L	update conflicts with concurrent update
isc_unlicensed	335544452L	product <string> is not licensed
isc_obj_in_use	335544453L	object <string> is in use
isc_nofilter	335544454L	filter not found to convert type <long> to type <long>
isc_shadow_accessed	335544455L	cannot attach active shadow file
isc_invalid_sdl	335544456L	invalid slice description language at offset <long>
isc_out_of_bounds	335544457L	subscript out of bounds
isc_invalid_dimension	335544458L	column not array or invalid dimensions (expected <long>, encountered <long>)
isc_rec_in_limbo	335544459L	record from transaction <long> is stuck in limbo
isc_shadow_missing	335544460L	a file in manual shadow <long> is unavailable
isc_cant_validate	335544461L	secondary server attachments cannot validate databases
isc_cant_start_journal	335544462L	secondary server attachments cannot start journaling
isc_gennotdef	335544463L	generator <string> is not defined
isc_cant_start _logging	335544464L	secondary server attachments cannot start logging
isc_bad_segstr_type	335544465L	invalid BLOB type for operation
isc_foreign_key	335544466L	violation of FOREIGN KEY constraint: "<string>"
isc_high_minor	335544467L	minor version too high found <long> expected <long>
isc_tra_state	335544468L	transaction <long> is <string>
isc_trans_invalid	335544469L	transaction marked invalid by I/O error
isc_buf_invalid	335544470L	cache buffer for page <long> invalid
isc_indexnotdefined	335544471L	there is no index in table <string> with id <digit>
isc_login	335544472L	Your user name and password are not defined. Ask your database administrator to set up an InterBase login.
isc_invalid_bookmark	335544473L	invalid bookmark handle
isc_bad_lock_level	335544474L	invalid lock level <digit>
isc_relation_lock	335544475L	lock on table <string> conflicts with existing lock
isc_record_lock	335544476L	requested record lock conflicts with existing lock
isc_max_idx	335544477L	maximum indexes per table (<digit>) exceeded
isc_jrn_enable	335544478L	enable journal for database before starting online dump
isc_old_failure	335544479L	online dump failure. Retry dump
isc_old_in_progress	335544480L	an online dump is already in progress
isc_old_no_space	335544481L	no more disk/tape space. Cannot continue online dump
isc_no_wal_no_jrn	335544482L	journaling allowed only if database has Write-ahead Log
isc_num_old_files	335544483L	maximum number of online dump files that can be specified is 16
isc_wal_file_open	335544484L	error in opening Write-ahead Log file during recovery
isc_bad_stmt_handle	335544485L	invalid statement handle
isc_wal_failure	335544486L	Write-ahead log subsystem failure
isc_walw_err	335544487L	WAL Writer error
isc_logh_small	335544488L	Log file header of <string> too small
isc_logh_inv_version	335544489L	Invalid version of log file <string>
isc_logh_open_flag	335544490L	Log file <string> not latest in the chain but open flag still set
isc_logh_open_flag2	335544491L	Log file <string> not closed properly; database recovery may be required
isc_logh_diff_dbname	335544492L	Database name in the log file <string> is different
isc_logf_unexpected _eof	335544493L	Unexpected end of log file <string> at offset <long>
isc_logr_incomplete	335544494L	Incomplete log record at offset <long> in log file <string>
isc_logr_header _small	335544495L	Log record header too small at offset <long> in log file <string>
isc_logb_small	335544496L	Log block too small at offset <long> in log file <string>
isc_wal_illegal_attach	335544497L	Illegal attempt to attach to an uninitialized WAL segment for <string>
isc_wal_invalid_wpb	335544498L	Invalid WAL parameter block option <string>
isc_wal_err_rollover	335544499L	Cannot roll over to the next log file <string>
isc_no_wal	335544500L	database does not use Write-ahead Log
isc_drop_wal	335544501L	cannot drop log file when journaling is enabled
isc_stream_not _defined	335544502L	reference to invalid stream number
isc_wal_subsys_error	335544503L	WAL subsystem encountered error
isc_wal_subsys _corrupt	335544504L	WAL subsystem corrupted
isc_no_archive	335544505L	must specify archive file when enabling long-term journal for databases with round-robin log files
isc_shutinprog	335544506L	database <string> shutdown in progress
isc_range_in_use	335544507L	refresh range number <long> already in use
isc_range_not_found	335544508L	refresh range number <long> not found
isc_charset_not _found	335544509L	CHARACTER SET <string> is not defined
isc_lock_timeout	335544510L	lock time-out on wait transaction
isc_prcnotdef	335544511L	procedure <string> is not defined
isc_prcmismat	335544512L	parameter mismatch for procedure <string>
isc_wal_bugcheck	335544513L	Database <string>: WAL subsystem bug for pid <digit>\
isc_wal_cant_expand	335544514L	Could not expand the WAL segment for database <string>
isc_codnotdef	335544515L	status code <string> unknown
isc_xcpnotdef	335544516L	exception <string> not defined
isc_except	335544517L	exception <digit>
isc_cache_restart	335544518L	restart shared cache manager
isc_bad_lock_handle	335544519L	invalid lock handle
isc_jrn_present	335544520L	long-term journaling already enabled
isc_wal_err_rollover2	335544521L	Unable to roll over; please see InterBase log.
isc_wal_err_logwrite	335544522L	WAL I/O error. Please see InterBase log.
isc_wal_err_jrn _comm	335544523L	WAL writer - Journal server communication error. Please see InterBase log.
isc_wal_err _expansion	335544524L	WAL buffers cannot be increased. Please see InterBase log.
isc_wal_err_setup	335544525L	WAL setup error. Please see InterBase log.
isc_wal_err_ww_sync	335544526L	WAL writer synchronization error for the database <string>
isc_wal_err_ww_start	335544527L	Cannot start WAL writer for the database <string>
isc_shutdown	335544528L	database <string> shutdown
isc_existing_priv_mod	335544529L	cannot modify an existing user privilege
isc_primary_key_ref	335544530L	Cannot delete PRIMARY KEY being used in FOREIGN KEY definition.
isc_primary_key _notnull	335544531L	Column used in a PRIMARY/UNIQUE constraint must be NOT NULL.
isc_ref_cnstrnt _notfound	335544532L	Name of Referential Constraint not defined in constraints table.
isc_foreign_key _notfound	335544533L	Non-existent PRIMARY or UNIQUE KEY specified for FOREIGN KEY.
isc_ref_cnstrnt _update	335544534L	Cannot update constraints (RDB$REF_CONSTRAINTS).
isc_check_cnstrnt _update	335544535L	Cannot update constraints (RDB$CHECK_CONSTRAINTS).
isc_check_cnstrnt_del	335544536L	Cannot delete CHECK constraint entry (RDB$CHECK_CONSTRAINTS)
isc_integ_index_seg _del	335544537L	Cannot delete index segment used by an Integrity Constraint
isc_integ_index_seg _mod	335544538L	Cannot update index segment used by an Integrity Constraint
isc_integ_index_del	335544539L	Cannot delete index used by an Integrity Constraint
isc_integ_index_mod	335544540L	Cannot modify index used by an Integrity Constraint
isc_check_trig_del	335544541L	Cannot delete trigger used by a CHECK Constraint
isc_check_trig_update	335544542L	Cannot update trigger used by a CHECK Constraint
isc_cnstrnt_fld_del	335544543L	Cannot delete column being used in an Integrity Constraint.
isc_cnstrnt_fld _rename	335544544L	Cannot rename column being used in an Integrity Constraint.
isc_rel_cnstrnt _update	335544545L	Cannot update constraints (RDB$RELATION_CONSTRAINTS).
isc_constaint_on _view	335544546L	Cannot define constraints on views
isc_invld_cnstrnt_type	335544547L	internal isc software consistency check (invalid RDB$CONSTRAINT_TYPE)
isc_primary_key _exists	335544548L	Attempt to define a second PRIMARY KEY for the same table
isc_systrig_update	335544549L	cannot modify or erase a system trigger
isc_not_rel_owner	335544550L	only the owner of a table may reassign ownership
isc_grant_obj _notfound	335544551L	could not find table/procedure for GRANT
isc_grant_fld _notfound	335544552L	could not find column for GRANT
isc_grant_nopriv	335544553L	user does not have GRANT privileges for operation
isc_nonsql_security _rel	335544554L	table/procedure has non-SQL security class defined
isc_nonsql_security _fld	335544555L	column has non-SQL security class defined
isc_wal_cache_err	335544556L	Write-ahead Log without shared cache configuration not allowed
isc_shutfail	335544557L	database shutdown unsuccessful
isc_check_constraint	335544558L	Operation violates CHECK constraint <string> on view or table
isc_bad_svc_handle	335544559L	invalid service handle
isc_shutwarn	335544560L	database <string> shutdown in <digit> seconds
isc_wrospbver	335544561L	wrong version of service parameter block
isc_bad_spb_form	335544562L	unrecognized service parameter block
isc_svcnotdef	335544563L	service <string> is not defined
isc_no_jrn	335544564L	long-term journaling not enabled
isc_transliteration _failed	335544565L	Cannot transliterate character between character sets
isc_start_cm_for_wal	335544566L	WAL defined; Cache Manager must be started first
isc_wal_ovflow_log _required	335544567L	Overflow log specification required for round-robin log
isc_text_subtype	335544568L	Implementation of text subtype <digit> not located.
isc_dsql_error	335544569L	Dynamic SQL Error
isc_dsql_command _err	335544570L	Invalid command
isc_dsql_constant_err	335544571L	Data type for constant unknown
isc_dsql_cursor_err	335544572L	Cursor unknown
isc_dsql_datatype_err	335544573L	Data type unknown
isc_dsql_decl_err	335544574L	Declared cursor already exists
isc_dsql_cursor _update_err	335544575L	Cursor not updatable
isc_dsql_cursor_open_err	335544576L	Attempt to reopen an open cursor
isc_dsql_cursor_close_err	335544577L	Attempt to reclose a closed cursor
isc_dsql_field_err	335544578L	Column unknown
isc_dsql_internal_err	335544579L	Internal error
isc_dsql_relation_err	335544580L	Table unknown
isc_dsql_procedure _err	335544581L	Procedure unknown
isc_dsql_request_err	335544582L	Request unknown
isc_dsql_sqlda_err	335544583L	SQLDA missing or incorrect vresion, or incorrect number/type of variables
isc_dsql_var_count _err	335544584L	Count of columns not equal count of values
isc_dsql_stmt_handle	335544585L	Invalid statement handle
isc_dsql_function_err	335544586L	Function unknown
isc_dsql_blob_err	335544587L	Column is not a BLOB
isc_collation_not _found	335544588L	COLLATION <string> is not defined
isc_collation_not_for _charset	335544589L	COLLATION <string> is not valid for specified CHARACTER SET
isc_dsql_dup_option	335544590L	Option specified more than once
isc_dsql_tran_err	335544591L	Unknown transaction option
isc_dsql_invalid_array	335544592L	Invalid array reference
isc_dsql_max_arr _dim_exceeded	335544593L	Array declared with too many dimensions
isc_dsql_arr_range _error	335544594L	Illegal array dimension range
isc_dsql_trigger_err	335544595L	Trigger unknown
isc_dsql_subselect _err	335544596L	Subselect illegal in this context
isc_dsql_crdb _prepare_err	335544597L	Cannot prepare a CREATE DATABASE/SCHEMA statement
isc_specify_field_err	335544598L	must specify column name for view select expression
isc_num_field_err	335544599L	number of columns does not match select list
isc_col_name_err	335544600L	Only simple column names permitted for VIEW WITH CHECK OPTION
isc_where_err	335544601L	No WHERE clause for VIEW WITH CHECK OPTION
isc_table_view_err	335544602L	Only one table allowed for VIEW WITH CHECK OPTION
isc_distinct_err	335544603L	DISTINCT, GROUP or HAVING not permitted for VIEW WITH CHECK OPTION
isc_key_field_count _err	335544604L	FOREIGN KEY column count does not match PRIMARY KEY
isc_subquery_err	335544605L	No subqueries permitted for VIEW WITH CHECK OPTION
isc_expression_eval _err	335544606L	expression evaluation not supported
isc_node_err	335544607L	gen.c: node not supported
isc_command_end _err	335544608L	Unexpected end of command
isc_index_name	335544609L	INDEX <string>
isc_exception_name	335544610L	EXCEPTION <string>
isc_field_name	335544611L	COLUMN <string>
isc_token_err	335544612L	Token unknown
isc_union_err	335544613L	union not supported
isc_dsql_construct _err	335544614L	Unsupported DSQL construct
isc_field_aggregate _err	335544615L	column used with aggregate
isc_field_ref_err	335544616L	invalid column reference
isc_order_by_err	335544617L	invalid ORDER BY clause
isc_return_mode_err	335544618L	Return mode by value not allowed for this data type
isc_extern_func_err	335544619L	External functions cannot have more than 10 parameters
isc_alias_conflict_err	335544620L	alias <string> conflicts with an alias in the same statement
isc_procedure_conflict_error	335544621L	alias <string> conflicts with a procedure in the same statement
isc_relation_conflict _err	335544622L	alias <string> conflicts with a table in the same statement
isc_dsql_domain_err	335544623L	Illegal use of keyword VALUE
isc_idx_seg_err	335544624L	segment count of 0 defined for index <string>
isc_node_name_err	335544625L	A node name is not permitted in a secondary, shadow, cache or log file name
isc_table_name	335544626L	TABLE <string>
isc_proc_name	335544627L	PROCEDURE <string>
isc_idx_create_err	335544628L	cannot create index <string>
isc_wal_shadow_err	335544629L	Write-ahead Log with shadowing configuration not allowed
isc_dependency	335544630L	there are <long> dependencies
isc_idx_key_err	335544631L	too many keys defined for index <string>
isc_dsql_file_length _err	335544632L	Preceding file did not specify length, so <string> must include starting page number
isc_dsql_shadow _number_err	335544633L	Shadow number must be a positive integer
isc_dsql_token_unk _err	335544634L	Token unknown - line <long>, char <long>
isc_dsql_no_relation _alias	335544635L	there is no alias or table named <string> at this scope level
isc_indexname	335544636L	there is no index <string> for table <string>
isc_no_stream_plan	335544637L	table <string> is not referenced in plan
isc_stream_twice	335544638L	table <string> is referenced more than once in plan; use aliases to distinguish
isc_stream_not_found	335544639L	table <string> is referenced in the plan but not the from list
isc_collation_requires_text	335544640L	Invalid use of CHARACTER SET or COLLATE
isc_dsql_domain_not_found	335544641L	Specified domain or source column does not exist
isc_index_unused	335544642L	index <string> cannot be used in the specified plan
isc_dsql_self_join	335544643L	the table <string> is referenced twice; use aliases to differentiate
isc_stream_bof	335544644L	illegal operation when at beginning of stream
isc_stream_crack	335544645L	the current position is on a crack
isc_db_or_file_exists	335544646L	database or file exists
isc_invalid_operator	335544647L	invalid comparison operator for find operation
isc_conn_lost	335544648L	Connection lost to pipe server
isc_bad_checksum	335544649L	bad checksum
isc_page_type_err	335544650L	wrong page type
isc_ext_readonly_err	335544651L	external file could not be opened for output
isc_sing_select_err	335544652L	multiple rows in singleton select
isc_psw_attach	335544653L	cannot attach to password database
isc_psw_start_trans	335544654L	cannot start transaction for password database
isc_invalid_direction	335544655L	invalid direction for find operation
isc_dsql_var_conflict	335544656L	variable <string> conflicts with parameter in same procedure
isc_dsql_no_blob _array	335544657L	Array/BLOB/DATE data types not allowed in arithmetic
isc_dsql_base_table	335544658L	<string> is not a valid base table of the specified view
isc_duplicate_base _table	335544659L	table <string> is referenced twice in view; use an alias to distinguish
isc_view_alias	335544660L	view <string> has more than one base table; use aliases to distinguish
isc_index_root_page _full	335544661L	cannot add index, index root page is full.
isc_dsql_blob_type _unknown	335544662L	BLOB SUB_TYPE <string> is not defined
isc_req_max_clones _exceeded	335544663L	Too many concurrent executions of the same request
isc_dsql_duplicate _spec	335544664L	duplicate specification of <string> - not supported
isc_unique_key _violation	335544665L	violation of PRIMARY or UNIQUE KEY constraint: "<string>"
isc_srvr_version_too _old	335544666L	server version too old to support all CREATE DATABASE options
isc_drdb_completed _with_errs	335544667L	drop database completed with errors
isc_dsql_procedure _use_err	335544668L	procedure <string> does not return any values
isc_dsql_count _mismatch	335544669L	count of column list and variable list do not match
isc_blob_idx_err	335544670L	attempt to index BLOB column in index <string>
isc_array_idx_err	335544671L	attempt to index array column in index <string>
isc_key_field_err	335544672L	too few key columns found for index <string> (incorrect column name?)
isc_no_delete	335544673L	cannot delete
isc_del_last_field	335544674L	last column in a table cannot be deleted
isc_sort_err	335544675L	sort error
isc_sort_mem_err	335544676L	sort error: not enough memory
isc_version_err	335544677L	too many versions
isc_inval_key_posn	335544678L	invalid key position
isc_no_segments_err	335544679L	segments not allowed in expression index <string>
isc_crrp_data_err	335544680L	sort error: corruption in data structure
isc_rec_size_err	335544681L	new record size of <long> bytes is too big
isc_dsql_field_ref	335544682L	Inappropriate self-reference of column
isc_req_depth _exceeded	335544683L	request depth exceeded. (Recursive definition?)
isc_no_field_access	335544684L	cannot access column <string> in view <string>
isc_no_dbkey	335544685L	dbkey not available for multi-table views
isc_jrn_format_err	335544686L	journal file wrong format
isc_jrn_file_full	335544687L	intermediate journal file full
isc_dsql_open_cursor_request	335544688L	The prepare statement identifies a prepare statement with an open cursor
isc_ib_error	335544689L	InterBase error
isc_cache_redef	335544690L	Cache redefined
isc_cache_too_small	335544691L	Cache length too small
isc_log_redef	335544692L	Log redefined
isc_log_too_small	335544693L	Log size too small
isc_partition_too _small	335544694L	Log partition size too small
isc_partition_not _supp	335544695L	Partitions not supported in series of log file specification
isc_log_length_spec	335544696L	Total length of a partitioned log must be specified
isc_precision_err	335544697L	Precision should be greater than 0
isc_scale_nogt	335544698L	Scale cannot be greater than precision
isc_expec_short	335544699L	Short integer expected
isc_expec_long	335544700L	Long integer expected
isc_expec_ushort	335544701L	Unsigned short integer expected
isc_like_escape _invalid	335544702L	Invalid ESCAPE sequence
isc_svcnoexe	335544703L	service <string> does not have an associated executable
isc_net_lookup_err	335544704L	Network lookup failure for host "<string>"
isc_service_unknown	335544705L	Undefined service <string>/<string>
isc_host_unknown	335544706L	Host unknown
isc_grant_nopriv_on _base	335544707L	user does not have GRANT privileges on base table/view for operation
isc_dyn_fld _ambiguous	335544708L	Ambiguous column reference.
isc_dsql_agg_ref_err	335544709L	Invalid aggregate reference
isc_complex_view	335544710L	navigational stream <long> references a view with more than one base table.
isc_unprepared_stmt	335544711L	attempt to execute an unprepared dynamic SQL statement
isc_expec_positive	335544712L	Positive value expected.
isc_dsql_sqlda_value_err	335544713L	Incorrect values within SQLDA structure
isc_invalid_array_id	335544714L	invalid blob id
isc_ext_file_uns_op	335544715L	Operation not supported for EXTERNAL FILE table <string>


Server Manager Error Messages

This table lists the error messages generated by the Server Manager during database backup and restoration. Along with the text of each error message is a suggested action to correct the problem.

Error Message	Causes and Suggested Actions to Take

Array dimension for column <string> is invalid	Fix the array definition before backing up.
Bad attribute for RDB$CHARACTER_SETS	An incompatible character set is in use.
Bad attribute for RDB$COLLATIONS	Fix the attribute in the named system table.
Bad attribute for table constraint	Check integrity constraints; if restoring, consider using the "no validity" option to delete validity constraints.
Blocking factor parameter missing	Supply a numeric argument for "factor" option.
Cannot commit files	Database may contain corruption, or metadata may violate integrity constraints. Try restoring tables using "one at a time" option, or delete validity constraints using "no validity" option.
Cannot commit index <string>	Data may conflict with defined indexes. Try restoring using "inactive" option to prevent rebuilding indexes.
Cannot find column for BLOB
Cannot find table <string>
Cannot open backup file <string>	Correct the file name you supplied and try again.
Cannot open status and error output file <string>	Messages are being redirected to invalid file name. Check format of file or access permissions on the directory of output file.
Column <string> used in index <string> seems to have vanished	An index references a non-existent column. Check either the index definition or column definition.
Commit failed on table <string>	Data corruption or violation of integrity constraint in the specified table. Check metadata or restore "one table at a time."
Could not drop database <string> (database might be in use)	You used the Replace Existing Database option in restoring a file to an existing database, but the database is in use. Either rename the target database or wait until it is not in use.
Could not open file name <string>	Fix the file name and re-execute command.
Could not read from file <string>	Fix the file name and re-execute command.
Could not write to file <string>	Fix the file name and re-execute command.
Data type n not understood	An illegal data type is being specified.
Database format n is too old to restore to	The server version is incompatible with the version of the database.
Database <string> already exists. To replace it, use the -R switch	The target database for restoration already exists. Either rename the target database or use the Replace Existing Database option.
Do not recognize record type n
Do not recognize <string> attribute n -- continuing
Do not understand BLOB INFO item n
Error accessing BLOB column <string> -- continuing
ERROR: Backup incomplete	The backup cannot be written to the target device or file system. Either there is insufficient space, a hardware write problem, or data corruption.
Error committing metadata for table <string>	A table within the database may be corrupt. If restoring a database, try using the "Commit After Each Table" option to isolate the table.
Exiting before completion due to errors	This message accompanies other error messages and indicates that back up or restore could not execute. Check other error messages for the cause.
Expected array dimension m but instead found n	The problem array may need to be redefined.
Expected array version number m but found n	The problem array may need to be redefined.
Expected backup database <string>, found <string>	Check the name of the backup file being restored.
Expected backup description record
Expected backup start time <string>, found <string>
Expected backup version 1, 2, or 3. Found n
Expected data attribute
Expected database description record
Expected number of bytes to be skipped, encountered <string>
Expected record length
Expected volume number m, found volume n	When backing up or restoring with multiple tapes, be sure to specify the correct volume number.
Expected XDR record length
Failed in put_blr_gen_id
Failed in store_blr_gen_id
Failed to create database <string>	The target database specified is invalid. It may already exist.
Index <string> omitted because m of the expected n keys were found
Input and output have the same name. Disallowed.	A backup file and database must have unique names. Correct the names and try again.
Length given for initial file (m) is less than minimum (n)	In restoring a database into multiple files, the primary file was not allocated sufficient space. InterBase automatically increases the page length to the minimum value. No action necessary.
Missing parameter for the number of bytes to be skipped
Multiple sources or destinations specified	Only one device name can be specified as a source or target.
No table name for data	The database contains data that is unassigned to a table. Use Server Manager to validate or mend the database.
Page size specified (n bytes) rounded up to n bytes	Invalid page sizes are rounded up to 1024, 2048, 4096, or 8192, whichever is closest.
Page size specified (n) greater than limit (8192 bytes)	Specify a page size of 1024, 2048, 4096, or 8192.
Protection is not there yet
Requires both input and output file names	Specify both a source and target when backing up or restoring.
Restore failed for record in table <string>	Possible data corruption in the named table.
Skipped n bytes after reading a bad attribute n
Skipped n bytes looking for next valid attribute, encountered attribute n
Trigger <string> is invalid
Unexpected end of file on backup file	Restoration of the backup file failed. The backup procedure that created the backup file may have terminated abnormally. If possible, create a new backup file and use it to restore the database.
Unexpected I/O error while <string> backup file	A disk error or other hardware error may have occurred during a backup or restore.
User name parameter missing	The backup or restore is accessing a remote machine. Supply a user name.
Validation error on column in table <string>	The database cannot be restored because it contains data that violates integrity constraints. It may be necessary to delete constraints from the metadata by specifying the "Do Not Restore Validity Conditions" during restore.
Warning -- record could not be restored	Possible corruption of the named data.
Wrong length record, expected m encountered n